2023-07-26 19:54:36 +01:00
|
|
|
// Copyright (c) Tailscale Inc & AUTHORS
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
|
|
|
|
package magicsock
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/netip"
|
|
|
|
|
2023-09-11 18:13:00 +01:00
|
|
|
"tailscale.com/tailcfg"
|
2023-07-26 19:54:36 +01:00
|
|
|
"tailscale.com/types/key"
|
2023-09-11 18:13:00 +01:00
|
|
|
"tailscale.com/util/set"
|
2023-07-26 19:54:36 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// peerInfo is all the information magicsock tracks about a particular
|
|
|
|
// peer.
|
|
|
|
type peerInfo struct {
|
|
|
|
ep *endpoint // always non-nil.
|
|
|
|
// ipPorts is an inverted version of peerMap.byIPPort (below), so
|
|
|
|
// that when we're deleting this node, we can rapidly find out the
|
|
|
|
// keys that need deleting from peerMap.byIPPort without having to
|
|
|
|
// iterate over every IPPort known for any peer.
|
2023-09-11 18:13:00 +01:00
|
|
|
ipPorts set.Set[netip.AddrPort]
|
2023-07-26 19:54:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func newPeerInfo(ep *endpoint) *peerInfo {
|
|
|
|
return &peerInfo{
|
|
|
|
ep: ep,
|
2023-09-11 18:13:00 +01:00
|
|
|
ipPorts: set.Set[netip.AddrPort]{},
|
2023-07-26 19:54:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// peerMap is an index of peerInfos by node (WireGuard) key, disco
|
|
|
|
// key, and discovered ip:port endpoints.
|
|
|
|
//
|
2023-09-11 18:13:00 +01:00
|
|
|
// It doesn't do any locking; all access must be done with Conn.mu held.
|
2023-07-26 19:54:36 +01:00
|
|
|
type peerMap struct {
|
|
|
|
byNodeKey map[key.NodePublic]*peerInfo
|
|
|
|
byIPPort map[netip.AddrPort]*peerInfo
|
2023-09-11 18:13:00 +01:00
|
|
|
byNodeID map[tailcfg.NodeID]*peerInfo
|
2023-07-26 19:54:36 +01:00
|
|
|
|
|
|
|
// nodesOfDisco contains the set of nodes that are using a
|
|
|
|
// DiscoKey. Usually those sets will be just one node.
|
2023-09-11 18:13:00 +01:00
|
|
|
nodesOfDisco map[key.DiscoPublic]set.Set[key.NodePublic]
|
2023-07-26 19:54:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func newPeerMap() peerMap {
|
|
|
|
return peerMap{
|
|
|
|
byNodeKey: map[key.NodePublic]*peerInfo{},
|
|
|
|
byIPPort: map[netip.AddrPort]*peerInfo{},
|
2023-09-11 18:13:00 +01:00
|
|
|
byNodeID: map[tailcfg.NodeID]*peerInfo{},
|
|
|
|
nodesOfDisco: map[key.DiscoPublic]set.Set[key.NodePublic]{},
|
2023-07-26 19:54:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// nodeCount returns the number of nodes currently in m.
|
|
|
|
func (m *peerMap) nodeCount() int {
|
2023-09-11 18:13:00 +01:00
|
|
|
if len(m.byNodeKey) != len(m.byNodeID) {
|
|
|
|
devPanicf("internal error: peerMap.byNodeKey and byNodeID out of sync")
|
|
|
|
}
|
2023-07-26 19:54:36 +01:00
|
|
|
return len(m.byNodeKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
// anyEndpointForDiscoKey reports whether there exists any
|
|
|
|
// peers in the netmap with dk as their DiscoKey.
|
|
|
|
func (m *peerMap) anyEndpointForDiscoKey(dk key.DiscoPublic) bool {
|
|
|
|
return len(m.nodesOfDisco[dk]) > 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// endpointForNodeKey returns the endpoint for nk, or nil if
|
|
|
|
// nk is not known to us.
|
|
|
|
func (m *peerMap) endpointForNodeKey(nk key.NodePublic) (ep *endpoint, ok bool) {
|
|
|
|
if nk.IsZero() {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
if info, ok := m.byNodeKey[nk]; ok {
|
|
|
|
return info.ep, true
|
|
|
|
}
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
|
2023-09-11 18:13:00 +01:00
|
|
|
// endpointForNodeID returns the endpoint for nodeID, or nil if
|
|
|
|
// nodeID is not known to us.
|
|
|
|
func (m *peerMap) endpointForNodeID(nodeID tailcfg.NodeID) (ep *endpoint, ok bool) {
|
|
|
|
if info, ok := m.byNodeID[nodeID]; ok {
|
|
|
|
return info.ep, true
|
|
|
|
}
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
|
2023-07-26 19:54:36 +01:00
|
|
|
// endpointForIPPort returns the endpoint for the peer we
|
|
|
|
// believe to be at ipp, or nil if we don't know of any such peer.
|
|
|
|
func (m *peerMap) endpointForIPPort(ipp netip.AddrPort) (ep *endpoint, ok bool) {
|
|
|
|
if info, ok := m.byIPPort[ipp]; ok {
|
|
|
|
return info.ep, true
|
|
|
|
}
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
|
|
|
|
// forEachEndpoint invokes f on every endpoint in m.
|
|
|
|
func (m *peerMap) forEachEndpoint(f func(ep *endpoint)) {
|
|
|
|
for _, pi := range m.byNodeKey {
|
|
|
|
f(pi.ep)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// forEachEndpointWithDiscoKey invokes f on every endpoint in m that has the
|
|