device: add API for on-demand configuration of peers

Updates tailscale/tailscale#17858

Signed-off-by: Brad Fitzpatrick <brad@danga.com>
This commit is contained in:
Brad Fitzpatrick 2025-11-12 13:04:17 -08:00 committed by 世界
parent 70b09a6edd
commit e924a91e99
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
5 changed files with 151 additions and 10 deletions

View file

@ -8,6 +8,8 @@ package device
import (
"container/list"
"errors"
"net/netip"
"slices"
"sync"
"sync/atomic"
"time"
@ -27,6 +29,12 @@ type Peer struct {
queuedOutboundPackets atomic.Int32 // packets in staged+outbound queues, for input backpressure
// deleteOnIdle indicates whether the peer should be deleted when idle
// because it was auto-created via a Device.PeerLookupFunc.
//
// This field should only be set once, before the peer is started.
deleteOnIdle bool
endpoint struct {
sync.Mutex
val conn.Endpoint
@ -46,7 +54,9 @@ type Peer struct {
}
state struct {
sync.Mutex // protects against concurrent Start/Stop
sync.Mutex // protects against concurrent Start/Stop, and fields below
allowedIPs []netip.Prefix
}
queue struct {
@ -89,7 +99,7 @@ func (device *Device) NewPeer(pk NoisePublicKey) (*Peer, error) {
// map public key
_, ok := device.peers.keyMap[pk]
if ok {
return nil, errors.New("adding existing peer")
return nil, errAddExistingPeer
}
// pre-compute DH
@ -115,6 +125,22 @@ func (device *Device) NewPeer(pk NoisePublicKey) (*Peer, error) {
return peer, nil
}
// SetAllowedIPs sets the allowed IP prefixes for this peer.
//
// If the allowedIPs are unchanged since the last call, this method is a no-op.
// It's the caller's responsibility to ensure that no two peers have duplicate
// allowed IPs. If so, the last writer wins.
func (p *Peer) SetAllowedIPs(allowedIPs []netip.Prefix) {
p.state.Lock()
defer p.state.Unlock()
if slices.Equal(p.state.allowedIPs, allowedIPs) {
return
}
p.device.allowedips.setPeerPrefixes(p, allowedIPs)
p.state.allowedIPs = slices.Clone(allowedIPs) // avoid retaining caller's slice
}
// SendBuffers sends buffers to peer. WireGuard packet data in each element of
// buffers must be preceded by MessageEncapsulatingTransportSize number of
// bytes.