mirror of
https://github.com/tailscale/tailscale.git
synced 2026-10-23 03:37:19 +09:00
wgengine: support per-peer WireGuard PSKs
Replace the allowed-IP-only peer callback result with wgcfg.PeerConfig. It carries allowed IPs and an optional pre-shared key through lazy peer creation and active peer synchronization. Update wireguard-go for the new peer PSK APIs. Updates tailscale/tailcat#84 Change-Id: Iacd9d2c74b0b64d690f3cbdf93918686ac6076d7 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
1 parent
9ea7cba445
commit
31d8badb3b
21 files changed
+86
-54
No files matched your search
@@ -120,6 +120,7 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/
|
||||
github.com/tailscale/wireguard-go/replay from github.com/tailscale/wireguard-go/device
|
||||
github.com/tailscale/wireguard-go/rwcancel from github.com/tailscale/wireguard-go/device+
|
||||
github.com/tailscale/wireguard-go/tai64n from github.com/tailscale/wireguard-go/device
|
||||
💣 github.com/tailscale/wireguard-go/tsasm/amd64/chacha20poly1305 from github.com/tailscale/wireguard-go/device
|
||||
💣 github.com/tailscale/wireguard-go/tun from github.com/tailscale/wireguard-go/device+
|
||||
github.com/x448/float16 from github.com/fxamacker/cbor/v2
|
||||
go.opentelemetry.io/otel/attribute from go.opentelemetry.io/otel/trace+
|
||||
|
||||
@@ -34,6 +34,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
github.com/tailscale/wireguard-go/replay from github.com/tailscale/wireguard-go/device
|
||||
github.com/tailscale/wireguard-go/rwcancel from github.com/tailscale/wireguard-go/device+
|
||||
github.com/tailscale/wireguard-go/tai64n from github.com/tailscale/wireguard-go/device
|
||||
💣 github.com/tailscale/wireguard-go/tsasm/amd64/chacha20poly1305 from github.com/tailscale/wireguard-go/device
|
||||
💣 github.com/tailscale/wireguard-go/tun from github.com/tailscale/wireguard-go/device+
|
||||
💣 go4.org/mem from tailscale.com/control/controlbase+
|
||||
go4.org/netipx from tailscale.com/ipn/ipnlocal+
|
||||
|
||||
@@ -39,6 +39,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
github.com/tailscale/wireguard-go/replay from github.com/tailscale/wireguard-go/device
|
||||
github.com/tailscale/wireguard-go/rwcancel from github.com/tailscale/wireguard-go/device+
|
||||
github.com/tailscale/wireguard-go/tai64n from github.com/tailscale/wireguard-go/device
|
||||
💣 github.com/tailscale/wireguard-go/tsasm/amd64/chacha20poly1305 from github.com/tailscale/wireguard-go/device
|
||||
💣 github.com/tailscale/wireguard-go/tun from github.com/tailscale/wireguard-go/device+
|
||||
💣 go4.org/mem from tailscale.com/control/controlbase+
|
||||
go4.org/netipx from tailscale.com/ipn/ipnlocal+
|
||||
|
||||
@@ -201,6 +201,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
github.com/tailscale/wireguard-go/replay from github.com/tailscale/wireguard-go/device
|
||||
github.com/tailscale/wireguard-go/rwcancel from github.com/tailscale/wireguard-go/device+
|
||||
github.com/tailscale/wireguard-go/tai64n from github.com/tailscale/wireguard-go/device
|
||||
💣 github.com/tailscale/wireguard-go/tsasm/amd64/chacha20poly1305 from github.com/tailscale/wireguard-go/device
|
||||
💣 github.com/tailscale/wireguard-go/tun from github.com/tailscale/wireguard-go/device+
|
||||
github.com/tailscale/xnet/webdav from tailscale.com/drive/driveimpl+
|
||||
github.com/tailscale/xnet/webdav/internal/xml from github.com/tailscale/xnet/webdav
|
||||
|
||||
@@ -71,6 +71,7 @@ tailscale.com/cmd/tsidp dependencies: (generated by github.com/tailscale/depawar
|
||||
github.com/tailscale/wireguard-go/replay from github.com/tailscale/wireguard-go/device
|
||||
github.com/tailscale/wireguard-go/rwcancel from github.com/tailscale/wireguard-go/device+
|
||||
github.com/tailscale/wireguard-go/tai64n from github.com/tailscale/wireguard-go/device
|
||||
💣 github.com/tailscale/wireguard-go/tsasm/amd64/chacha20poly1305 from github.com/tailscale/wireguard-go/device
|
||||
💣 github.com/tailscale/wireguard-go/tun from github.com/tailscale/wireguard-go/device+
|
||||
github.com/x448/float16 from github.com/fxamacker/cbor/v2
|
||||
💣 go4.org/mem from tailscale.com/client/local+
|
||||
|
||||
@@ -173,4 +173,4 @@
|
||||
});
|
||||
};
|
||||
}
|
||||
# nix-direnv cache busting line: sha256-h3KPqXE1Wvl1nfUmus0zWowaiqBIxz6eJT/+dIBEkOM=
|
||||
# nix-direnv cache busting line: sha256-w7VuEoXsnL7wmHbKlwd6qgUqyRj09JAqHw073Zgnidc=
|
||||
+2
-2
@@ -4,7 +4,7 @@
|
||||
"sri": "sha256-+cTlDLusJthxTayVx6yGoqZHRN4ylvs/9Qpy4P2dlDI="
|
||||
},
|
||||
"vendor": {
|
||||
"goModSum": "sha256-MRFSK8wD2bSzZ/Tnhx2Z+EuF4jqj6D91chMIaB6hnzQ=",
|
||||
"sri": "sha256-h3KPqXE1Wvl1nfUmus0zWowaiqBIxz6eJT/+dIBEkOM="
|
||||
"goModSum": "sha256-aYPi3BUkgTUZ3ESpK33W2CtHruPSgb7gMJlAP/tUL0I=",
|
||||
"sri": "sha256-w7VuEoXsnL7wmHbKlwd6qgUqyRj09JAqHw073Zgnidc="
|
||||
}
|
||||
}
|
||||
@@ -126,7 +126,7 @@ require (
|
||||
github.com/tailscale/ts-gokrazy v0.0.0-20260630224145-b83088f2e52e
|
||||
github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976
|
||||
github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6
|
||||
github.com/tailscale/wireguard-go v0.0.0-20260821191448-23d18d66172c
|
||||
github.com/tailscale/wireguard-go v0.0.0-20260904023712-e855235c55a2
|
||||
github.com/tailscale/xnet v0.0.0-20240729143630-8497ac4dab2e
|
||||
github.com/tc-hib/winres v0.2.1
|
||||
github.com/tcnksm/go-httpstat v0.2.0
|
||||
|
||||
@@ -1217,8 +1217,8 @@ github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 h1:U
|
||||
github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976/go.mod h1:agQPE6y6ldqCOui2gkIh7ZMztTkIQKH049tv8siLuNQ=
|
||||
github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6 h1:l10Gi6w9jxvinoiq15g8OToDdASBni4CyJOdHY1Hr8M=
|
||||
github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6/go.mod h1:ZXRML051h7o4OcI0d3AaILDIad/Xw0IkXaHM17dic1Y=
|
||||
github.com/tailscale/wireguard-go v0.0.0-20260821191448-23d18d66172c h1:rjqTtbumXpM5B1UR7u+dsOaI9wRetOfIDan5kJJrgn8=
|
||||
github.com/tailscale/wireguard-go v0.0.0-20260821191448-23d18d66172c/go.mod h1:6SerzcvHWQchKO2BfNdmquA77CHSECZuFl+D9fp4RnI=
|
||||
github.com/tailscale/wireguard-go v0.0.0-20260904023712-e855235c55a2 h1:nRCnARSGqRvSAK9S+vbH87dMykfv2vWwx6kb8rw9Ayk=
|
||||
github.com/tailscale/wireguard-go v0.0.0-20260904023712-e855235c55a2/go.mod h1:rUelGmuK4UnSJYM5gl5Mknp6YbwwcL8+VAPMhNYe+jg=
|
||||
github.com/tailscale/xnet v0.0.0-20240729143630-8497ac4dab2e h1:zOGKqN5D5hHhiYUp091JqK7DPCqSARyUfduhGUY8Bek=
|
||||
github.com/tailscale/xnet v0.0.0-20240729143630-8497ac4dab2e/go.mod h1:orPd6JZXXRyuDusYilywte7k094d7dycXXU5YnWsrwg=
|
||||
github.com/tc-hib/winres v0.2.1 h1:YDE0FiP0VmtRaDn7+aaChp1KiF4owBiJa5l964l5ujA=
|
||||
|
||||
@@ -619,7 +619,7 @@ func NewLocalBackend(logf logger.Logf, logID logid.PublicID, sys *tsd.System, lo
|
||||
nb.ready()
|
||||
|
||||
e.SetPeerByIPPacketFunc(b.lookupPeerByIP)
|
||||
e.SetPeerConfigFunc(b.peerAllowedIPs)
|
||||
e.SetPeerConfigFunc(b.peerConfig)
|
||||
e.SetPeerForIPFunc(b.PeerForIP)
|
||||
e.SetPeerSessionStateFunc(b.onPeerWireGuardState)
|
||||
e.SetNetLogSource(netLogNodeSource{b})
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/util/dnsname"
|
||||
"tailscale.com/wgengine"
|
||||
"tailscale.com/wgengine/wgcfg"
|
||||
)
|
||||
|
||||
// lookupPeerByIP returns the node public key for the peer that should
|
||||
@@ -40,14 +41,14 @@ func (b *LocalBackend) lookupPeerByIP(ip netip.Addr) (key.NodePublic, bool) {
|
||||
return key.NodePublic{}, false
|
||||
}
|
||||
|
||||
// peerAllowedIPs returns the prefixes from which the peer with the
|
||||
// given public key is currently allowed to originate traffic, or
|
||||
// ok=false if the peer is unknown (or currently routable via no
|
||||
// peerConfig returns the WireGuard configuration for the peer with the given
|
||||
// public key, or ok=false if the peer is unknown (or currently routable via no
|
||||
// prefix at all). It is installed as the
|
||||
// [wgengine.Engine.SetPeerConfigFunc] callback, backing wireguard-go's
|
||||
// lazy peer creation and per-delta peer sync.
|
||||
func (b *LocalBackend) peerAllowedIPs(k key.NodePublic) (_ []netip.Prefix, ok bool) {
|
||||
return b.currentNode().PeerAllowedIPs(k)
|
||||
func (b *LocalBackend) peerConfig(k key.NodePublic) (_ wgcfg.PeerConfig, ok bool) {
|
||||
ips, ok := b.currentNode().PeerAllowedIPs(k)
|
||||
return wgcfg.PeerConfig{AllowedIPs: ips}, ok
|
||||
}
|
||||
|
||||
// resolveMagicDNS resolves a MagicDNS hostname to the owning node's IP
|
||||
|
||||
@@ -1884,7 +1884,7 @@ type mockEngine struct {
|
||||
|
||||
filter, jailedFilter *filter.Filter
|
||||
|
||||
peerConfigFn func(key.NodePublic) (allowedIPs []netip.Prefix, ok bool)
|
||||
peerConfigFn func(key.NodePublic) (config wgcfg.PeerConfig, ok bool)
|
||||
|
||||
statusCb wgengine.StatusCallback
|
||||
}
|
||||
@@ -1991,7 +1991,7 @@ func (e *mockEngine) InstallCaptureHook(packet.CaptureCallback) {}
|
||||
|
||||
func (e *mockEngine) SetPeerByIPPacketFunc(func(netip.Addr) (_ key.NodePublic, ok bool)) {}
|
||||
func (e *mockEngine) SetPeerForIPFunc(func(netip.Addr) (_ wgengine.PeerForIP, ok bool)) {}
|
||||
func (e *mockEngine) SetPeerConfigFunc(fn func(key.NodePublic) (allowedIPs []netip.Prefix, ok bool)) {
|
||||
func (e *mockEngine) SetPeerConfigFunc(fn func(key.NodePublic) (config wgcfg.PeerConfig, ok bool)) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
e.peerConfigFn = fn
|
||||
@@ -2006,14 +2006,15 @@ func (e *mockEngine) PeerAllowedIPs(k key.NodePublic) (_ []netip.Prefix, ok bool
|
||||
if fn == nil {
|
||||
return nil, false
|
||||
}
|
||||
return fn(k)
|
||||
conf, ok := fn(k)
|
||||
return conf.AllowedIPs, ok
|
||||
}
|
||||
|
||||
func (e *mockEngine) SyncDevicePeer(key.NodePublic) {}
|
||||
func (e *mockEngine) SyncDevicePeer(key.NodePublic) {}
|
||||
func (e *mockEngine) MarkDevicePeerForHandshake(key.NodePublic) {}
|
||||
func (e *mockEngine) SetPeerSessionStateFunc(func(key.NodePublic, wgengine.PeerWireGuardState)) {
|
||||
}
|
||||
func (e *mockEngine) SetNetLogSource(wgengine.NetLogSource) {}
|
||||
func (e *mockEngine) SetNetLogSource(wgengine.NetLogSource) {}
|
||||
func (e *mockEngine) SetPeerPriorityMessageOnEstablishmentFunc(fn func(key.NodePublic) (msg []byte)) {
|
||||
}
|
||||
func (e *mockEngine) SetWGPeerLookup(func(wgString string) (tsString string, ok bool)) {}
|
||||
|
||||
@@ -16,4 +16,4 @@
|
||||
) {
|
||||
src = ./.;
|
||||
}).shellNix
|
||||
# nix-direnv cache busting line: sha256-h3KPqXE1Wvl1nfUmus0zWowaiqBIxz6eJT/+dIBEkOM=
|
||||
# nix-direnv cache busting line: sha256-w7VuEoXsnL7wmHbKlwd6qgUqyRj09JAqHw073Zgnidc=
|
||||
@@ -71,6 +71,7 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware)
|
||||
github.com/tailscale/wireguard-go/replay from github.com/tailscale/wireguard-go/device
|
||||
github.com/tailscale/wireguard-go/rwcancel from github.com/tailscale/wireguard-go/device+
|
||||
github.com/tailscale/wireguard-go/tai64n from github.com/tailscale/wireguard-go/device
|
||||
💣 github.com/tailscale/wireguard-go/tsasm/amd64/chacha20poly1305 from github.com/tailscale/wireguard-go/device
|
||||
💣 github.com/tailscale/wireguard-go/tun from github.com/tailscale/wireguard-go/device+
|
||||
github.com/x448/float16 from github.com/fxamacker/cbor/v2
|
||||
💣 go4.org/mem from tailscale.com/client/local+
|
||||
|
||||
@@ -92,17 +92,17 @@ func setupWGTest(b *testing.B, logf logger.Logf, traf *TrafficGen, a1, a2 netip.
|
||||
e2.SetPeerByIPPacketFunc(func(dst netip.Addr) (_ key.NodePublic, ok bool) {
|
||||
return k1pub, a1.Contains(dst)
|
||||
})
|
||||
e1.SetPeerConfigFunc(func(pubk key.NodePublic) (_ []netip.Prefix, ok bool) {
|
||||
e1.SetPeerConfigFunc(func(pubk key.NodePublic) (_ wgcfg.PeerConfig, ok bool) {
|
||||
if pubk == k2pub {
|
||||
return []netip.Prefix{a2}, true
|
||||
return wgcfg.PeerConfig{AllowedIPs: []netip.Prefix{a2}}, true
|
||||
}
|
||||
return nil, false
|
||||
return wgcfg.PeerConfig{}, false
|
||||
})
|
||||
e2.SetPeerConfigFunc(func(pubk key.NodePublic) (_ []netip.Prefix, ok bool) {
|
||||
e2.SetPeerConfigFunc(func(pubk key.NodePublic) (_ wgcfg.PeerConfig, ok bool) {
|
||||
if pubk == k1pub {
|
||||
return []netip.Prefix{a1}, true
|
||||
return wgcfg.PeerConfig{AllowedIPs: []netip.Prefix{a1}}, true
|
||||
}
|
||||
return nil, false
|
||||
return wgcfg.PeerConfig{}, false
|
||||
})
|
||||
|
||||
var wait sync.WaitGroup
|
||||
|
||||
@@ -305,10 +305,11 @@ func (s *magicStack) Reconfig(cfg *wgcfg.Config, peers []tailcfg.NodeView) error
|
||||
})
|
||||
|
||||
// The live per-peer config source backing lazy peer creation, as
|
||||
// LocalBackend's peerAllowedIPs does via PeerAllowedIPs, and the
|
||||
// LocalBackend's peerConfig does via PeerAllowedIPs, and the
|
||||
// per-peer device convergence that Engine.SyncDevicePeer does.
|
||||
s.dev.SetPeerLookupFunc(wgcfg.NewPeerLookupFunc(s.conn.Bind(), s.conn.logf, func(pubk device.NoisePublicKey) ([]netip.Prefix, bool) {
|
||||
return peerAllowedIPs(key.NodePublicFromRaw32(mem.B(pubk[:])))
|
||||
s.dev.SetPeerLookupFunc(wgcfg.NewPeerLookupFunc(s.conn.Bind(), s.conn.logf, func(pubk device.NoisePublicKey) (wgcfg.PeerConfig, bool) {
|
||||
ips, ok := peerAllowedIPs(key.NodePublicFromRaw32(mem.B(pubk[:])))
|
||||
return wgcfg.PeerConfig{AllowedIPs: ips}, ok
|
||||
}))
|
||||
s.dev.SetPrivateKey(key.NodePrivateAs[device.NoisePrivateKey](cfg.PrivateKey))
|
||||
s.dev.RemoveMatchingPeers(func(pk device.NoisePublicKey) bool {
|
||||
|
||||
@@ -109,11 +109,11 @@ type userspaceEngine struct {
|
||||
// for the cold-path control lookups (Ping, TSMP, pendopen, etc).
|
||||
peerForIPFn atomic.Pointer[func(netip.Addr) (_ PeerForIP, ok bool)]
|
||||
|
||||
// peerConfigFn, if non-nil, is the live per-peer allowed-IPs
|
||||
// peerConfigFn, if non-nil, is the live per-peer WireGuard config
|
||||
// source installed via [userspaceEngine.SetPeerConfigFunc]. When
|
||||
// set, wgdev's PeerLookupFunc queries it directly, so reconfigs
|
||||
// no longer install per-config lookup closures.
|
||||
peerConfigFn atomic.Pointer[func(key.NodePublic) (allowedIPs []netip.Prefix, ok bool)]
|
||||
peerConfigFn atomic.Pointer[func(key.NodePublic) (config wgcfg.PeerConfig, ok bool)]
|
||||
|
||||
lastCfg wgcfg.Config
|
||||
lastRouter *router.Config
|
||||
@@ -672,14 +672,14 @@ func (e *userspaceEngine) handleLocalPackets(p *packet.Parsed, t *tstun.Wrapper)
|
||||
|
||||
// SetPeerConfigFunc implements [Engine.SetPeerConfigFunc]. It stores
|
||||
// fn and installs a single wgdev PeerLookupFunc wrapping it, so
|
||||
// lazily-created peers always get current allowed IPs and the lookup
|
||||
// lazily-created peers always get their current config and the lookup
|
||||
// func never needs to be reinstalled as the peer set changes.
|
||||
func (e *userspaceEngine) SetPeerConfigFunc(fn func(key.NodePublic) (allowedIPs []netip.Prefix, ok bool)) {
|
||||
func (e *userspaceEngine) SetPeerConfigFunc(fn func(key.NodePublic) (config wgcfg.PeerConfig, ok bool)) {
|
||||
if fn == nil {
|
||||
panic("SetPeerConfigFunc: nil fn")
|
||||
}
|
||||
e.peerConfigFn.Store(&fn)
|
||||
e.wgdev.SetPeerLookupFunc(wgcfg.NewPeerLookupFunc(e.wgdev.Bind(), e.logf, func(pubk device.NoisePublicKey) ([]netip.Prefix, bool) {
|
||||
e.wgdev.SetPeerLookupFunc(wgcfg.NewPeerLookupFunc(e.wgdev.Bind(), e.logf, func(pubk device.NoisePublicKey) (wgcfg.PeerConfig, bool) {
|
||||
return fn(key.NodePublicFromRaw32(mem.B(pubk[:])))
|
||||
}))
|
||||
}
|
||||
@@ -695,13 +695,14 @@ func (e *userspaceEngine) SyncDevicePeer(k key.NodePublic) {
|
||||
// The peer set may be about to change; drop the wgLogger's cached
|
||||
// peer-string rewrites so the next log line re-resolves them.
|
||||
e.wgLogger.Invalidate()
|
||||
allowedIPs, ok := (*fn)(k)
|
||||
conf, ok := (*fn)(k)
|
||||
if !ok {
|
||||
e.wgdev.RemovePeer(k.Raw32())
|
||||
return
|
||||
}
|
||||
if peer, ok := e.wgdev.LookupActivePeer(k.Raw32()); ok {
|
||||
peer.SetAllowedIPs(allowedIPs)
|
||||
peer.SetPresharedKey(conf.PresharedKey)
|
||||
peer.SetAllowedIPs(conf.AllowedIPs)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"net/netip"
|
||||
"slices"
|
||||
|
||||
"github.com/tailscale/wireguard-go/device"
|
||||
"tailscale.com/types/key"
|
||||
)
|
||||
|
||||
@@ -17,13 +18,23 @@ import (
|
||||
// It only supports the set of things Tailscale uses.
|
||||
//
|
||||
// Peers are not part of the config: wireguard-go learns the peer set
|
||||
// and each peer's allowed IPs from the live per-peer config source
|
||||
// and each peer's configuration from the live per-peer config source
|
||||
// installed via [tailscale.com/wgengine.Engine.SetPeerConfigFunc].
|
||||
type Config struct {
|
||||
PrivateKey key.NodePrivate
|
||||
Addresses []netip.Prefix
|
||||
}
|
||||
|
||||
// PeerConfig is the WireGuard configuration for one peer.
|
||||
type PeerConfig struct {
|
||||
// AllowedIPs is the set of prefixes the peer may originate traffic from.
|
||||
AllowedIPs []netip.Prefix
|
||||
|
||||
// PresharedKey is the optional WireGuard pre-shared key. The zero value
|
||||
// disables the pre-shared-key layer.
|
||||
PresharedKey device.NoisePresharedKey
|
||||
}
|
||||
|
||||
func (c *Config) Equal(o *Config) bool {
|
||||
if c == nil || o == nil {
|
||||
return c == o
|
||||
|
||||
@@ -5,7 +5,6 @@ package wgcfg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
|
||||
"github.com/tailscale/wireguard-go/conn"
|
||||
"github.com/tailscale/wireguard-go/device"
|
||||
@@ -19,11 +18,12 @@ func NewDevice(tunDev tun.Device, bind conn.Bind, logger *device.Logger) *device
|
||||
}
|
||||
|
||||
// NewPeerLookupFunc returns a [device.PeerLookupFunc] that lazily
|
||||
// creates peers using allowedIPs as the source of each peer's allowed
|
||||
// IPs. The peer's endpoint is derived from its public key via bind.
|
||||
func NewPeerLookupFunc(bind conn.Bind, logf logger.Logf, allowedIPs func(device.NoisePublicKey) ([]netip.Prefix, bool)) device.PeerLookupFunc {
|
||||
// creates peers using peerConfig as the source of each peer's allowed IPs and
|
||||
// optional pre-shared key. The peer's endpoint is derived from its public key
|
||||
// via bind.
|
||||
func NewPeerLookupFunc(bind conn.Bind, logf logger.Logf, peerConfig func(device.NoisePublicKey) (PeerConfig, bool)) device.PeerLookupFunc {
|
||||
return func(pubk device.NoisePublicKey) (_ *device.NewPeerConfig, ok bool) {
|
||||
ips, ok := allowedIPs(pubk)
|
||||
conf, ok := peerConfig(pubk)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
@@ -33,8 +33,9 @@ func NewPeerLookupFunc(bind conn.Bind, logf logger.Logf, allowedIPs func(device.
|
||||
return nil, false
|
||||
}
|
||||
return &device.NewPeerConfig{
|
||||
AllowedIPs: ips,
|
||||
Endpoint: ep,
|
||||
AllowedIPs: conf.AllowedIPs,
|
||||
PresharedKey: conf.PresharedKey,
|
||||
Endpoint: ep,
|
||||
}, true
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"io"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/tailscale/wireguard-go/conn"
|
||||
@@ -28,12 +29,13 @@ func TestNewPeerLookupFunc(t *testing.T) {
|
||||
|
||||
// peers is the live per-peer config source, standing in for what
|
||||
// LocalBackend provides via wgengine.Engine.SetPeerConfigFunc.
|
||||
peers := map[device.NoisePublicKey][]netip.Prefix{
|
||||
k2.Raw32(): {ip2},
|
||||
psk2 := device.NoisePresharedKey{1, 2, 3}
|
||||
peers := map[device.NoisePublicKey]PeerConfig{
|
||||
k2.Raw32(): {AllowedIPs: []netip.Prefix{ip2}, PresharedKey: psk2},
|
||||
}
|
||||
dev.SetPeerLookupFunc(NewPeerLookupFunc(dev.Bind(), t.Logf, func(pubk device.NoisePublicKey) ([]netip.Prefix, bool) {
|
||||
ips, ok := peers[pubk]
|
||||
return ips, ok
|
||||
dev.SetPeerLookupFunc(NewPeerLookupFunc(dev.Bind(), t.Logf, func(pubk device.NoisePublicKey) (PeerConfig, bool) {
|
||||
conf, ok := peers[pubk]
|
||||
return conf, ok
|
||||
}))
|
||||
|
||||
t.Run("lazy-creation", func(t *testing.T) {
|
||||
@@ -42,6 +44,13 @@ func TestNewPeerLookupFunc(t *testing.T) {
|
||||
if p := dev.LookupPeer(k2.Raw32()); p == nil {
|
||||
t.Fatal("expected peer k2 to exist via LookupPeer")
|
||||
}
|
||||
got, err := dev.IpcGet()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if want := "preshared_key=0102030000000000000000000000000000000000000000000000000000000000"; !strings.Contains(got, want) {
|
||||
t.Fatalf("device config does not contain %q:\n%s", want, got)
|
||||
}
|
||||
// An unknown peer should not be found.
|
||||
if p := dev.LookupPeer(k3.Raw32()); p != nil {
|
||||
t.Fatal("expected unknown peer k3 to not exist")
|
||||
|
||||
@@ -185,10 +185,10 @@ type Engine interface {
|
||||
SetPeerByIPPacketFunc(func(netip.Addr) (_ key.NodePublic, ok bool))
|
||||
|
||||
// SetPeerConfigFunc installs the live source of per-peer WireGuard
|
||||
// configuration: given a peer's public key, fn returns the prefixes
|
||||
// the peer is currently allowed to originate traffic from, or
|
||||
// ok=false if the peer is unknown (in which case it must not exist
|
||||
// in the WireGuard device). The engine installs a single
|
||||
// configuration: given a peer's public key, fn returns its current
|
||||
// WireGuard configuration, including the prefixes it may originate and
|
||||
// its optional pre-shared key. It returns ok=false if the peer is unknown,
|
||||
// in which case it must not exist in the WireGuard device. The engine installs a single
|
||||
// [device.PeerLookupFunc] wrapping fn, so lazily-created peers
|
||||
// always see current state and the lookup func never needs to be
|
||||
// reinstalled as peers come and go.
|
||||
@@ -197,14 +197,15 @@ type Engine interface {
|
||||
// before the first [Engine.Reconfig]. fn is called rarely (when
|
||||
// wireguard-go first hears from a peer it doesn't have) and may
|
||||
// acquire locks.
|
||||
SetPeerConfigFunc(fn func(key.NodePublic) (allowedIPs []netip.Prefix, ok bool))
|
||||
SetPeerConfigFunc(fn func(key.NodePublic) (config wgcfg.PeerConfig, ok bool))
|
||||
|
||||
// SyncDevicePeer synchronizes the WireGuard device's state for a
|
||||
// single peer with the config source installed via
|
||||
// [Engine.SetPeerConfigFunc]: if the source no longer knows the
|
||||
// peer, it is removed from the device; if the peer is active in the
|
||||
// device, its allowed IPs are updated. It does O(1) work (plus the
|
||||
// config source lookup) and is intended to be called for each peer
|
||||
// device, its allowed IPs and pre-shared key are updated. It does O(1)
|
||||
// work (plus the config source lookup) and is intended to be called for
|
||||
// each peer
|
||||
// added, updated, or removed by an incremental netmap delta,
|
||||
// avoiding a full [Engine.Reconfig].
|
||||
//
|
||||
|
||||
Reference in new issue
Block a user