mirror of
https://github.com/tailscale/tailscale.git
synced 2026-05-05 20:26:47 +02:00
Replace the UAPI text protocol-based wireguard configuration with wireguard-go's new direct callback API (SetPeerLookupFunc, SetPeerByIPPacketFunc, RemoveMatchingPeers, SetPrivateKey). Instead of computing a trimmed wireguard config ahead of time upon control plane updates and pushing it via UAPI, install callbacks so wireguard-go creates peers on demand when packets arrive. This removes all the LazyWG trimming machinery: idle peer tracking, activity maps, noteRecvActivity callbacks, the KeepFullWGConfig control knob, and the ts_omit_lazywg build tag. For incoming packets, PeerLookupFunc answers wireguard-go's questions about unknown public keys by looking up the peer in the full config. For outgoing packets, PeerByIPPacketFunc (installed from LocalBackend.lookupPeerByIP) maps destination IPs to node public keys using the existing nodeByAddr index. Updates tailscale/corp#12345 Change-Id: I4cba80979ac49a1231d00a01fdba5f0c2af95dd8 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
88 lines
2.6 KiB
Go
88 lines
2.6 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package wgcfg
|
|
|
|
import (
|
|
"fmt"
|
|
"net/netip"
|
|
|
|
"github.com/tailscale/wireguard-go/conn"
|
|
"github.com/tailscale/wireguard-go/device"
|
|
"github.com/tailscale/wireguard-go/tun"
|
|
"tailscale.com/types/logger"
|
|
)
|
|
|
|
// NewDevice returns a wireguard-go Device configured for Tailscale use.
|
|
func NewDevice(tunDev tun.Device, bind conn.Bind, logger *device.Logger) *device.Device {
|
|
ret := device.NewDevice(tunDev, bind, logger)
|
|
ret.DisableSomeRoamingForBrokenMobileSemantics()
|
|
return ret
|
|
}
|
|
|
|
// ReconfigDevice replaces the existing device configuration with cfg.
|
|
//
|
|
// Instead of using the UAPI text protocol, it uses the wireguard-go direct API
|
|
// to install a [device.PeerLookupFunc] callback that creates peers on demand.
|
|
//
|
|
// The caller is responsible for:
|
|
// - calling [device.Device.SetPrivateKey] when the key changes
|
|
// - installing a [device.PeerByIPPacketFunc] on the device for outbound
|
|
// packet routing (e.g. via [tailscale.com/wgengine.Engine.SetPeerByIPPacketFunc])
|
|
func ReconfigDevice(d *device.Device, cfg *Config, logf logger.Logf) (err error) {
|
|
defer func() {
|
|
if err != nil {
|
|
logf("wgcfg.Reconfig failed: %v", err)
|
|
}
|
|
}()
|
|
|
|
// Build peer map: public key → allowed IPs.
|
|
peers := make(map[device.NoisePublicKey][]netip.Prefix, len(cfg.Peers))
|
|
for _, p := range cfg.Peers {
|
|
peers[p.PublicKey.Raw32()] = p.AllowedIPs
|
|
}
|
|
|
|
// Remove peers not in the new config.
|
|
d.RemoveMatchingPeers(func(pk device.NoisePublicKey) bool {
|
|
_, exists := peers[pk]
|
|
return !exists
|
|
})
|
|
|
|
// Update AllowedIPs on any already-active peers whose config may have
|
|
// changed. Peers that don't exist yet will get the correct AllowedIPs
|
|
// from PeerLookupFunc when they are lazily created.
|
|
for pk, allowedIPs := range peers {
|
|
if peer, ok := d.LookupActivePeer(pk); ok {
|
|
peer.SetAllowedIPs(allowedIPs)
|
|
}
|
|
}
|
|
|
|
// Install callback for lazy peer creation (incoming packets).
|
|
bind := d.Bind()
|
|
d.SetPeerLookupFunc(func(pubk device.NoisePublicKey) (_ *device.NewPeerConfig, ok bool) {
|
|
allowedIPs, ok := peers[pubk]
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
ep, err := bind.ParseEndpoint(fmt.Sprintf("%x", pubk[:]))
|
|
if err != nil {
|
|
logf("wgcfg: failed to parse endpoint for peer %x: %v", pubk[:8], err)
|
|
return nil, false
|
|
}
|
|
return &device.NewPeerConfig{
|
|
AllowedIPs: allowedIPs,
|
|
Endpoint: ep,
|
|
}, true
|
|
})
|
|
|
|
// RemoveMatchingPeers _again_, now that SetPeerLookupFunc is installed,
|
|
// lest any removed peers got re-created before the new SetPeerLookupFunc
|
|
// func was installed.
|
|
d.RemoveMatchingPeers(func(pk device.NoisePublicKey) bool {
|
|
_, exists := peers[pk]
|
|
return !exists
|
|
})
|
|
|
|
return nil
|
|
}
|