mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-01 22:15:51 +00:00
types/netmap, all: use read-only tailcfg.NodeView in NetworkMap
Updates #8948 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
b040094b90
commit
58a4fd43d8
@ -257,21 +257,25 @@ func (i *jsIPN) run(jsCallbacks js.Value) {
|
|||||||
},
|
},
|
||||||
MachineStatus: jsMachineStatus[nm.MachineStatus],
|
MachineStatus: jsMachineStatus[nm.MachineStatus],
|
||||||
},
|
},
|
||||||
Peers: mapSlice(nm.Peers, func(p *tailcfg.Node) jsNetMapPeerNode {
|
Peers: mapSlice(nm.Peers, func(p tailcfg.NodeView) jsNetMapPeerNode {
|
||||||
name := p.Name
|
name := p.Name()
|
||||||
if name == "" {
|
if name == "" {
|
||||||
// In practice this should only happen for Hello.
|
// In practice this should only happen for Hello.
|
||||||
name = p.Hostinfo.Hostname()
|
name = p.Hostinfo().Hostname()
|
||||||
|
}
|
||||||
|
addrs := make([]string, p.Addresses().Len())
|
||||||
|
for i := range p.Addresses().LenIter() {
|
||||||
|
addrs[i] = p.Addresses().At(i).Addr().String()
|
||||||
}
|
}
|
||||||
return jsNetMapPeerNode{
|
return jsNetMapPeerNode{
|
||||||
jsNetMapNode: jsNetMapNode{
|
jsNetMapNode: jsNetMapNode{
|
||||||
Name: name,
|
Name: name,
|
||||||
Addresses: mapSlice(p.Addresses, func(a netip.Prefix) string { return a.Addr().String() }),
|
Addresses: addrs,
|
||||||
MachineKey: p.Machine.String(),
|
MachineKey: p.Machine().String(),
|
||||||
NodeKey: p.Key.String(),
|
NodeKey: p.Key().String(),
|
||||||
},
|
},
|
||||||
Online: p.Online,
|
Online: p.Online(),
|
||||||
TailscaleSSHEnabled: p.Hostinfo.TailscaleSSHEnabled(),
|
TailscaleSSHEnabled: p.Hostinfo().TailscaleSSHEnabled(),
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
LockedOut: nm.TKAEnabled && len(nm.SelfNode.KeySignature) == 0,
|
LockedOut: nm.TKAEnabled && len(nm.SelfNode.KeySignature) == 0,
|
||||||
|
@ -144,11 +144,18 @@ func (ms *mapSession) netmapForResponse(resp *tailcfg.MapResponse) *netmap.Netwo
|
|||||||
ms.lastTKAInfo = resp.TKAInfo
|
ms.lastTKAInfo = resp.TKAInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(bradfitz): now that this is a view, remove some of the defensive
|
||||||
|
// cloning elsewhere in mapSession.
|
||||||
|
peerViews := make([]tailcfg.NodeView, len(resp.Peers))
|
||||||
|
for i, n := range resp.Peers {
|
||||||
|
peerViews[i] = n.View()
|
||||||
|
}
|
||||||
|
|
||||||
nm := &netmap.NetworkMap{
|
nm := &netmap.NetworkMap{
|
||||||
NodeKey: ms.privateNodeKey.Public(),
|
NodeKey: ms.privateNodeKey.Public(),
|
||||||
PrivateKey: ms.privateNodeKey,
|
PrivateKey: ms.privateNodeKey,
|
||||||
MachineKey: ms.machinePubKey,
|
MachineKey: ms.machinePubKey,
|
||||||
Peers: resp.Peers,
|
Peers: peerViews,
|
||||||
UserProfiles: make(map[tailcfg.UserID]tailcfg.UserProfile),
|
UserProfiles: make(map[tailcfg.UserID]tailcfg.UserProfile),
|
||||||
Domain: ms.lastDomain,
|
Domain: ms.lastDomain,
|
||||||
DomainAuditLogID: ms.lastDomainAuditLogID,
|
DomainAuditLogID: ms.lastDomainAuditLogID,
|
||||||
|
@ -38,6 +38,14 @@ func ips(ss ...string) (ips []netip.Addr) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func nodeViews(v []*tailcfg.Node) []tailcfg.NodeView {
|
||||||
|
nv := make([]tailcfg.NodeView, len(v))
|
||||||
|
for i, n := range v {
|
||||||
|
nv[i] = n.View()
|
||||||
|
}
|
||||||
|
return nv
|
||||||
|
}
|
||||||
|
|
||||||
func TestDNSConfigForNetmap(t *testing.T) {
|
func TestDNSConfigForNetmap(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@ -62,7 +70,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
|
|||||||
nm: &netmap.NetworkMap{
|
nm: &netmap.NetworkMap{
|
||||||
Name: "myname.net",
|
Name: "myname.net",
|
||||||
Addresses: ipps("100.101.101.101"),
|
Addresses: ipps("100.101.101.101"),
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
Name: "peera.net",
|
Name: "peera.net",
|
||||||
Addresses: ipps("100.102.0.1", "100.102.0.2", "fe75::1001", "fe75::1002"),
|
Addresses: ipps("100.102.0.1", "100.102.0.2", "fe75::1001", "fe75::1002"),
|
||||||
@ -75,7 +83,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
|
|||||||
Name: "v6-only.net",
|
Name: "v6-only.net",
|
||||||
Addresses: ipps("fe75::3"), // no IPv4, so we don't ignore IPv6
|
Addresses: ipps("fe75::3"), // no IPv4, so we don't ignore IPv6
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
prefs: &ipn.Prefs{},
|
prefs: &ipn.Prefs{},
|
||||||
want: &dns.Config{
|
want: &dns.Config{
|
||||||
@ -96,7 +104,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
|
|||||||
nm: &netmap.NetworkMap{
|
nm: &netmap.NetworkMap{
|
||||||
Name: "myname.net",
|
Name: "myname.net",
|
||||||
Addresses: ipps("fe75::1"),
|
Addresses: ipps("fe75::1"),
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
Name: "peera.net",
|
Name: "peera.net",
|
||||||
Addresses: ipps("100.102.0.1", "100.102.0.2", "fe75::1001"),
|
Addresses: ipps("100.102.0.1", "100.102.0.2", "fe75::1001"),
|
||||||
@ -109,7 +117,7 @@ func TestDNSConfigForNetmap(t *testing.T) {
|
|||||||
Name: "v6-only.net",
|
Name: "v6-only.net",
|
||||||
Addresses: ipps("fe75::3"), // no IPv4, so we don't ignore IPv6
|
Addresses: ipps("fe75::3"), // no IPv4, so we don't ignore IPv6
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
prefs: &ipn.Prefs{},
|
prefs: &ipn.Prefs{},
|
||||||
want: &dns.Config{
|
want: &dns.Config{
|
||||||
|
@ -87,24 +87,26 @@ func (em *expiryManager) flagExpiredPeers(netmap *netmap.NetworkMap, localNow ti
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, peer := range netmap.Peers {
|
for i, peer := range netmap.Peers {
|
||||||
// Nodes that don't expire have KeyExpiry set to the zero time;
|
// Nodes that don't expire have KeyExpiry set to the zero time;
|
||||||
// skip those and peers that are already marked as expired
|
// skip those and peers that are already marked as expired
|
||||||
// (e.g. from control).
|
// (e.g. from control).
|
||||||
if peer.KeyExpiry.IsZero() || peer.KeyExpiry.After(controlNow) {
|
if peer.KeyExpiry().IsZero() || peer.KeyExpiry().After(controlNow) {
|
||||||
delete(em.previouslyExpired, peer.StableID)
|
delete(em.previouslyExpired, peer.StableID())
|
||||||
continue
|
continue
|
||||||
} else if peer.Expired {
|
} else if peer.Expired() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !em.previouslyExpired[peer.StableID] {
|
if !em.previouslyExpired[peer.StableID()] {
|
||||||
em.logf("[v1] netmap: flagExpiredPeers: clearing expired peer %v", peer.StableID)
|
em.logf("[v1] netmap: flagExpiredPeers: clearing expired peer %v", peer.StableID())
|
||||||
em.previouslyExpired[peer.StableID] = true
|
em.previouslyExpired[peer.StableID()] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mut := peer.AsStruct()
|
||||||
|
|
||||||
// Actually mark the node as expired
|
// Actually mark the node as expired
|
||||||
peer.Expired = true
|
mut.Expired = true
|
||||||
|
|
||||||
// Control clears the Endpoints and DERP fields of expired
|
// Control clears the Endpoints and DERP fields of expired
|
||||||
// nodes; do so here as well. The Expired bool is the correct
|
// nodes; do so here as well. The Expired bool is the correct
|
||||||
@ -113,12 +115,14 @@ func (em *expiryManager) flagExpiredPeers(netmap *netmap.NetworkMap, localNow ti
|
|||||||
// NOTE: this is insufficient to actually break connectivity,
|
// NOTE: this is insufficient to actually break connectivity,
|
||||||
// since we discover endpoints via DERP, and due to DERP return
|
// since we discover endpoints via DERP, and due to DERP return
|
||||||
// path optimization.
|
// path optimization.
|
||||||
peer.Endpoints = nil
|
mut.Endpoints = nil
|
||||||
peer.DERP = ""
|
mut.DERP = ""
|
||||||
|
|
||||||
// Defense-in-depth: break the node's public key as well, in
|
// Defense-in-depth: break the node's public key as well, in
|
||||||
// case something tries to communicate.
|
// case something tries to communicate.
|
||||||
peer.Key = key.NodePublicWithBadOldPrefix(peer.Key)
|
mut.Key = key.NodePublicWithBadOldPrefix(peer.Key())
|
||||||
|
|
||||||
|
netmap.Peers[i] = mut.View()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,13 +148,13 @@ func (em *expiryManager) nextPeerExpiry(nm *netmap.NetworkMap, localNow time.Tim
|
|||||||
|
|
||||||
var nextExpiry time.Time // zero if none
|
var nextExpiry time.Time // zero if none
|
||||||
for _, peer := range nm.Peers {
|
for _, peer := range nm.Peers {
|
||||||
if peer.KeyExpiry.IsZero() {
|
if peer.KeyExpiry().IsZero() {
|
||||||
continue // tagged node
|
continue // tagged node
|
||||||
} else if peer.Expired {
|
} else if peer.Expired() {
|
||||||
// Peer already expired; Expired is set by the
|
// Peer already expired; Expired is set by the
|
||||||
// flagExpiredPeers function, above.
|
// flagExpiredPeers function, above.
|
||||||
continue
|
continue
|
||||||
} else if peer.KeyExpiry.Before(controlNow) {
|
} else if peer.KeyExpiry().Before(controlNow) {
|
||||||
// This peer already expired, and peer.Expired
|
// This peer already expired, and peer.Expired
|
||||||
// isn't set for some reason. Skip this node.
|
// isn't set for some reason. Skip this node.
|
||||||
continue
|
continue
|
||||||
@ -160,8 +164,8 @@ func (em *expiryManager) nextPeerExpiry(nm *netmap.NetworkMap, localNow time.Tim
|
|||||||
// an expiry; otherwise, only update if this node's expiry is
|
// an expiry; otherwise, only update if this node's expiry is
|
||||||
// sooner than the currently-stored one (since we want the
|
// sooner than the currently-stored one (since we want the
|
||||||
// soonest-occurring expiry time).
|
// soonest-occurring expiry time).
|
||||||
if nextExpiry.IsZero() || peer.KeyExpiry.Before(nextExpiry) {
|
if nextExpiry.IsZero() || peer.KeyExpiry().Before(nextExpiry) {
|
||||||
nextExpiry = peer.KeyExpiry
|
nextExpiry = peer.KeyExpiry()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,38 +44,38 @@ func TestFlagExpiredPeers(t *testing.T) {
|
|||||||
name string
|
name string
|
||||||
controlTime *time.Time
|
controlTime *time.Time
|
||||||
netmap *netmap.NetworkMap
|
netmap *netmap.NetworkMap
|
||||||
want []*tailcfg.Node
|
want []tailcfg.NodeView
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "no_expiry",
|
name: "no_expiry",
|
||||||
controlTime: &now,
|
controlTime: &now,
|
||||||
netmap: &netmap.NetworkMap{
|
netmap: &netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
n(1, "foo", timeInFuture),
|
n(1, "foo", timeInFuture),
|
||||||
n(2, "bar", timeInFuture),
|
n(2, "bar", timeInFuture),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
},
|
want: nodeViews([]*tailcfg.Node{
|
||||||
want: []*tailcfg.Node{
|
|
||||||
n(1, "foo", timeInFuture),
|
n(1, "foo", timeInFuture),
|
||||||
n(2, "bar", timeInFuture),
|
n(2, "bar", timeInFuture),
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "expiry",
|
name: "expiry",
|
||||||
controlTime: &now,
|
controlTime: &now,
|
||||||
netmap: &netmap.NetworkMap{
|
netmap: &netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
n(1, "foo", timeInFuture),
|
n(1, "foo", timeInFuture),
|
||||||
n(2, "bar", timeInPast),
|
n(2, "bar", timeInPast),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
},
|
want: nodeViews([]*tailcfg.Node{
|
||||||
want: []*tailcfg.Node{
|
|
||||||
n(1, "foo", timeInFuture),
|
n(1, "foo", timeInFuture),
|
||||||
n(2, "bar", timeInPast, func(n *tailcfg.Node) {
|
n(2, "bar", timeInPast, func(n *tailcfg.Node) {
|
||||||
n.Expired = true
|
n.Expired = true
|
||||||
n.Key = expiredKey
|
n.Key = expiredKey
|
||||||
}),
|
}),
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "bad_ControlTime",
|
name: "bad_ControlTime",
|
||||||
@ -83,29 +83,29 @@ func TestFlagExpiredPeers(t *testing.T) {
|
|||||||
controlTime: &timeBeforeEpoch,
|
controlTime: &timeBeforeEpoch,
|
||||||
|
|
||||||
netmap: &netmap.NetworkMap{
|
netmap: &netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
n(1, "foo", timeInFuture),
|
n(1, "foo", timeInFuture),
|
||||||
n(2, "bar", timeBeforeEpoch.Add(-1*time.Hour)), // before ControlTime
|
n(2, "bar", timeBeforeEpoch.Add(-1*time.Hour)), // before ControlTime
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
},
|
want: nodeViews([]*tailcfg.Node{
|
||||||
want: []*tailcfg.Node{
|
|
||||||
n(1, "foo", timeInFuture),
|
n(1, "foo", timeInFuture),
|
||||||
n(2, "bar", timeBeforeEpoch.Add(-1*time.Hour)), // should have expired, but ControlTime is before epoch
|
n(2, "bar", timeBeforeEpoch.Add(-1*time.Hour)), // should have expired, but ControlTime is before epoch
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "tagged_node",
|
name: "tagged_node",
|
||||||
controlTime: &now,
|
controlTime: &now,
|
||||||
netmap: &netmap.NetworkMap{
|
netmap: &netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
n(1, "foo", timeInFuture),
|
n(1, "foo", timeInFuture),
|
||||||
n(2, "bar", time.Time{}), // tagged node; zero expiry
|
n(2, "bar", time.Time{}), // tagged node; zero expiry
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
},
|
want: nodeViews([]*tailcfg.Node{
|
||||||
want: []*tailcfg.Node{
|
|
||||||
n(1, "foo", timeInFuture),
|
n(1, "foo", timeInFuture),
|
||||||
n(2, "bar", time.Time{}), // not expired
|
n(2, "bar", time.Time{}), // not expired
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
@ -147,10 +147,10 @@ func TestNextPeerExpiry(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "no_expiry",
|
name: "no_expiry",
|
||||||
netmap: &netmap.NetworkMap{
|
netmap: &netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
n(1, "foo", noExpiry),
|
n(1, "foo", noExpiry),
|
||||||
n(2, "bar", noExpiry),
|
n(2, "bar", noExpiry),
|
||||||
},
|
}),
|
||||||
SelfNode: n(3, "self", noExpiry),
|
SelfNode: n(3, "self", noExpiry),
|
||||||
},
|
},
|
||||||
want: noExpiry,
|
want: noExpiry,
|
||||||
@ -158,10 +158,10 @@ func TestNextPeerExpiry(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "future_expiry_from_peer",
|
name: "future_expiry_from_peer",
|
||||||
netmap: &netmap.NetworkMap{
|
netmap: &netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
n(1, "foo", noExpiry),
|
n(1, "foo", noExpiry),
|
||||||
n(2, "bar", timeInFuture),
|
n(2, "bar", timeInFuture),
|
||||||
},
|
}),
|
||||||
SelfNode: n(3, "self", noExpiry),
|
SelfNode: n(3, "self", noExpiry),
|
||||||
},
|
},
|
||||||
want: timeInFuture,
|
want: timeInFuture,
|
||||||
@ -169,10 +169,10 @@ func TestNextPeerExpiry(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "future_expiry_from_self",
|
name: "future_expiry_from_self",
|
||||||
netmap: &netmap.NetworkMap{
|
netmap: &netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
n(1, "foo", noExpiry),
|
n(1, "foo", noExpiry),
|
||||||
n(2, "bar", noExpiry),
|
n(2, "bar", noExpiry),
|
||||||
},
|
}),
|
||||||
SelfNode: n(3, "self", timeInFuture),
|
SelfNode: n(3, "self", timeInFuture),
|
||||||
},
|
},
|
||||||
want: timeInFuture,
|
want: timeInFuture,
|
||||||
@ -180,10 +180,10 @@ func TestNextPeerExpiry(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "future_expiry_from_multiple_peers",
|
name: "future_expiry_from_multiple_peers",
|
||||||
netmap: &netmap.NetworkMap{
|
netmap: &netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
n(1, "foo", timeInFuture),
|
n(1, "foo", timeInFuture),
|
||||||
n(2, "bar", timeInMoreFuture),
|
n(2, "bar", timeInMoreFuture),
|
||||||
},
|
}),
|
||||||
SelfNode: n(3, "self", noExpiry),
|
SelfNode: n(3, "self", noExpiry),
|
||||||
},
|
},
|
||||||
want: timeInFuture,
|
want: timeInFuture,
|
||||||
@ -191,9 +191,9 @@ func TestNextPeerExpiry(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "future_expiry_from_peer_and_self",
|
name: "future_expiry_from_peer_and_self",
|
||||||
netmap: &netmap.NetworkMap{
|
netmap: &netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
n(1, "foo", timeInMoreFuture),
|
n(1, "foo", timeInMoreFuture),
|
||||||
},
|
}),
|
||||||
SelfNode: n(2, "self", timeInFuture),
|
SelfNode: n(2, "self", timeInFuture),
|
||||||
},
|
},
|
||||||
want: timeInFuture,
|
want: timeInFuture,
|
||||||
@ -201,7 +201,7 @@ func TestNextPeerExpiry(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "only_self",
|
name: "only_self",
|
||||||
netmap: &netmap.NetworkMap{
|
netmap: &netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{},
|
Peers: nodeViews([]*tailcfg.Node{}),
|
||||||
SelfNode: n(1, "self", timeInFuture),
|
SelfNode: n(1, "self", timeInFuture),
|
||||||
},
|
},
|
||||||
want: timeInFuture,
|
want: timeInFuture,
|
||||||
@ -209,9 +209,9 @@ func TestNextPeerExpiry(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "peer_already_expired",
|
name: "peer_already_expired",
|
||||||
netmap: &netmap.NetworkMap{
|
netmap: &netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
n(1, "foo", timeInPast),
|
n(1, "foo", timeInPast),
|
||||||
},
|
}),
|
||||||
SelfNode: n(2, "self", timeInFuture),
|
SelfNode: n(2, "self", timeInFuture),
|
||||||
},
|
},
|
||||||
want: timeInFuture,
|
want: timeInFuture,
|
||||||
@ -219,9 +219,9 @@ func TestNextPeerExpiry(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "self_already_expired",
|
name: "self_already_expired",
|
||||||
netmap: &netmap.NetworkMap{
|
netmap: &netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
n(1, "foo", timeInFuture),
|
n(1, "foo", timeInFuture),
|
||||||
},
|
}),
|
||||||
SelfNode: n(2, "self", timeInPast),
|
SelfNode: n(2, "self", timeInPast),
|
||||||
},
|
},
|
||||||
want: timeInFuture,
|
want: timeInFuture,
|
||||||
@ -229,9 +229,9 @@ func TestNextPeerExpiry(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "all_nodes_already_expired",
|
name: "all_nodes_already_expired",
|
||||||
netmap: &netmap.NetworkMap{
|
netmap: &netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
n(1, "foo", timeInPast),
|
n(1, "foo", timeInPast),
|
||||||
},
|
}),
|
||||||
SelfNode: n(2, "self", timeInPast),
|
SelfNode: n(2, "self", timeInPast),
|
||||||
},
|
},
|
||||||
want: noExpiry,
|
want: noExpiry,
|
||||||
@ -263,9 +263,9 @@ func TestNextPeerExpiry(t *testing.T) {
|
|||||||
// If we don't adjust for the local time, this would return a
|
// If we don't adjust for the local time, this would return a
|
||||||
// time in the past.
|
// time in the past.
|
||||||
nm := &netmap.NetworkMap{
|
nm := &netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
n(1, "foo", timeInPast),
|
n(1, "foo", timeInPast),
|
||||||
},
|
}),
|
||||||
}
|
}
|
||||||
got := em.nextPeerExpiry(nm, now)
|
got := em.nextPeerExpiry(nm, now)
|
||||||
want := now.Add(30 * time.Second)
|
want := now.Add(30 * time.Second)
|
||||||
@ -275,24 +275,24 @@ func TestNextPeerExpiry(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatNodes(nodes []*tailcfg.Node) string {
|
func formatNodes(nodes []tailcfg.NodeView) string {
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
for i, n := range nodes {
|
for i, n := range nodes {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
sb.WriteString(", ")
|
sb.WriteString(", ")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&sb, "(%d, %q", n.ID, n.Name)
|
fmt.Fprintf(&sb, "(%d, %q", n.ID(), n.Name())
|
||||||
|
|
||||||
if n.Online != nil {
|
if n.Online() != nil {
|
||||||
fmt.Fprintf(&sb, ", online=%v", *n.Online)
|
fmt.Fprintf(&sb, ", online=%v", *n.Online())
|
||||||
}
|
}
|
||||||
if n.LastSeen != nil {
|
if n.LastSeen() != nil {
|
||||||
fmt.Fprintf(&sb, ", lastSeen=%v", n.LastSeen.Unix())
|
fmt.Fprintf(&sb, ", lastSeen=%v", n.LastSeen().Unix())
|
||||||
}
|
}
|
||||||
if n.Key != (key.NodePublic{}) {
|
if n.Key() != (key.NodePublic{}) {
|
||||||
fmt.Fprintf(&sb, ", key=%v", n.Key.String())
|
fmt.Fprintf(&sb, ", key=%v", n.Key().String())
|
||||||
}
|
}
|
||||||
if n.Expired {
|
if n.Expired() {
|
||||||
fmt.Fprintf(&sb, ", expired=true")
|
fmt.Fprintf(&sb, ", expired=true")
|
||||||
}
|
}
|
||||||
sb.WriteString(")")
|
sb.WriteString(")")
|
||||||
|
@ -204,7 +204,7 @@ type LocalBackend struct {
|
|||||||
// netMap is not mutated in-place once set.
|
// netMap is not mutated in-place once set.
|
||||||
netMap *netmap.NetworkMap
|
netMap *netmap.NetworkMap
|
||||||
nmExpiryTimer tstime.TimerController // for updating netMap on node expiry; can be nil
|
nmExpiryTimer tstime.TimerController // for updating netMap on node expiry; can be nil
|
||||||
nodeByAddr map[netip.Addr]*tailcfg.Node
|
nodeByAddr map[netip.Addr]tailcfg.NodeView
|
||||||
activeLogin string // last logged LoginName from netMap
|
activeLogin string // last logged LoginName from netMap
|
||||||
engineStatus ipn.EngineStatus
|
engineStatus ipn.EngineStatus
|
||||||
endpoints []tailcfg.Endpoint
|
endpoints []tailcfg.Endpoint
|
||||||
@ -684,13 +684,13 @@ func (b *LocalBackend) updateStatus(sb *ipnstate.StatusBuilder, extraLocked func
|
|||||||
if !prefs.ExitNodeID().IsZero() {
|
if !prefs.ExitNodeID().IsZero() {
|
||||||
if exitPeer, ok := b.netMap.PeerWithStableID(prefs.ExitNodeID()); ok {
|
if exitPeer, ok := b.netMap.PeerWithStableID(prefs.ExitNodeID()); ok {
|
||||||
var online = false
|
var online = false
|
||||||
if exitPeer.Online != nil {
|
if v := exitPeer.Online(); v != nil {
|
||||||
online = *exitPeer.Online
|
online = *v
|
||||||
}
|
}
|
||||||
s.ExitNodeStatus = &ipnstate.ExitNodeStatus{
|
s.ExitNodeStatus = &ipnstate.ExitNodeStatus{
|
||||||
ID: prefs.ExitNodeID(),
|
ID: prefs.ExitNodeID(),
|
||||||
Online: online,
|
Online: online,
|
||||||
TailscaleIPs: exitPeer.Addresses,
|
TailscaleIPs: exitPeer.Addresses().AsSlice(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -705,7 +705,7 @@ func (b *LocalBackend) updateStatus(sb *ipnstate.StatusBuilder, extraLocked func
|
|||||||
ss.DNSName = b.netMap.Name
|
ss.DNSName = b.netMap.Name
|
||||||
ss.UserID = b.netMap.User
|
ss.UserID = b.netMap.User
|
||||||
if sn := b.netMap.SelfNode; sn != nil {
|
if sn := b.netMap.SelfNode; sn != nil {
|
||||||
peerStatusFromNode(ss, sn)
|
peerStatusFromNode(ss, sn.View())
|
||||||
if c := sn.Capabilities; len(c) > 0 {
|
if c := sn.Capabilities; len(c) > 0 {
|
||||||
ss.Capabilities = append([]string(nil), c...)
|
ss.Capabilities = append([]string(nil), c...)
|
||||||
}
|
}
|
||||||
@ -735,28 +735,30 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
|
|||||||
exitNodeID := b.pm.CurrentPrefs().ExitNodeID()
|
exitNodeID := b.pm.CurrentPrefs().ExitNodeID()
|
||||||
for _, p := range b.netMap.Peers {
|
for _, p := range b.netMap.Peers {
|
||||||
var lastSeen time.Time
|
var lastSeen time.Time
|
||||||
if p.LastSeen != nil {
|
if p.LastSeen() != nil {
|
||||||
lastSeen = *p.LastSeen
|
lastSeen = *p.LastSeen()
|
||||||
}
|
}
|
||||||
var tailscaleIPs = make([]netip.Addr, 0, len(p.Addresses))
|
var tailscaleIPs = make([]netip.Addr, 0, p.Addresses().Len())
|
||||||
for _, addr := range p.Addresses {
|
for i := range p.Addresses().LenIter() {
|
||||||
|
addr := p.Addresses().At(i)
|
||||||
if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.Addr()) {
|
if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.Addr()) {
|
||||||
tailscaleIPs = append(tailscaleIPs, addr.Addr())
|
tailscaleIPs = append(tailscaleIPs, addr.Addr())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
online := p.Online()
|
||||||
ps := &ipnstate.PeerStatus{
|
ps := &ipnstate.PeerStatus{
|
||||||
InNetworkMap: true,
|
InNetworkMap: true,
|
||||||
UserID: p.User,
|
UserID: p.User(),
|
||||||
TailscaleIPs: tailscaleIPs,
|
TailscaleIPs: tailscaleIPs,
|
||||||
HostName: p.Hostinfo.Hostname(),
|
HostName: p.Hostinfo().Hostname(),
|
||||||
DNSName: p.Name,
|
DNSName: p.Name(),
|
||||||
OS: p.Hostinfo.OS(),
|
OS: p.Hostinfo().OS(),
|
||||||
LastSeen: lastSeen,
|
LastSeen: lastSeen,
|
||||||
Online: p.Online != nil && *p.Online,
|
Online: online != nil && *online,
|
||||||
ShareeNode: p.Hostinfo.ShareeNode(),
|
ShareeNode: p.Hostinfo().ShareeNode(),
|
||||||
ExitNode: p.StableID != "" && p.StableID == exitNodeID,
|
ExitNode: p.StableID() != "" && p.StableID() == exitNodeID,
|
||||||
SSH_HostKeys: p.Hostinfo.SSH_HostKeys().AsSlice(),
|
SSH_HostKeys: p.Hostinfo().SSH_HostKeys().AsSlice(),
|
||||||
Location: p.Hostinfo.Location(),
|
Location: p.Hostinfo().Location(),
|
||||||
}
|
}
|
||||||
peerStatusFromNode(ps, p)
|
peerStatusFromNode(ps, p)
|
||||||
|
|
||||||
@ -767,29 +769,29 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
|
|||||||
if u := peerAPIURL(nodeIP(p, netip.Addr.Is6), p6); u != "" {
|
if u := peerAPIURL(nodeIP(p, netip.Addr.Is6), p6); u != "" {
|
||||||
ps.PeerAPIURL = append(ps.PeerAPIURL, u)
|
ps.PeerAPIURL = append(ps.PeerAPIURL, u)
|
||||||
}
|
}
|
||||||
sb.AddPeer(p.Key, ps)
|
sb.AddPeer(p.Key(), ps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// peerStatusFromNode copies fields that exist in the Node struct for
|
// peerStatusFromNode copies fields that exist in the Node struct for
|
||||||
// current node and peers into the provided PeerStatus.
|
// current node and peers into the provided PeerStatus.
|
||||||
func peerStatusFromNode(ps *ipnstate.PeerStatus, n *tailcfg.Node) {
|
func peerStatusFromNode(ps *ipnstate.PeerStatus, n tailcfg.NodeView) {
|
||||||
ps.ID = n.StableID
|
ps.ID = n.StableID()
|
||||||
ps.Created = n.Created
|
ps.Created = n.Created()
|
||||||
ps.ExitNodeOption = tsaddr.ContainsExitRoutes(views.SliceOf(n.AllowedIPs))
|
ps.ExitNodeOption = tsaddr.ContainsExitRoutes(n.AllowedIPs())
|
||||||
if n.Tags != nil {
|
if n.Tags().Len() != 0 {
|
||||||
v := views.SliceOf(n.Tags)
|
v := n.Tags()
|
||||||
ps.Tags = &v
|
ps.Tags = &v
|
||||||
}
|
}
|
||||||
if n.PrimaryRoutes != nil {
|
if n.PrimaryRoutes().Len() != 0 {
|
||||||
v := views.SliceOf(n.PrimaryRoutes)
|
v := n.PrimaryRoutes()
|
||||||
ps.PrimaryRoutes = &v
|
ps.PrimaryRoutes = &v
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Expired {
|
if n.Expired() {
|
||||||
ps.Expired = true
|
ps.Expired = true
|
||||||
}
|
}
|
||||||
if t := n.KeyExpiry; !t.IsZero() {
|
if t := n.KeyExpiry(); !t.IsZero() {
|
||||||
t = t.Round(time.Second)
|
t = t.Round(time.Second)
|
||||||
ps.KeyExpiry = &t
|
ps.KeyExpiry = &t
|
||||||
}
|
}
|
||||||
@ -798,7 +800,8 @@ func peerStatusFromNode(ps *ipnstate.PeerStatus, n *tailcfg.Node) {
|
|||||||
// WhoIs reports the node and user who owns the node with the given IP:port.
|
// WhoIs reports the node and user who owns the node with the given IP:port.
|
||||||
// If the IP address is a Tailscale IP, the provided port may be 0.
|
// If the IP address is a Tailscale IP, the provided port may be 0.
|
||||||
// If ok == true, n and u are valid.
|
// If ok == true, n and u are valid.
|
||||||
func (b *LocalBackend) WhoIs(ipp netip.AddrPort) (n *tailcfg.Node, u tailcfg.UserProfile, ok bool) {
|
func (b *LocalBackend) WhoIs(ipp netip.AddrPort) (n tailcfg.NodeView, u tailcfg.UserProfile, ok bool) {
|
||||||
|
var zero tailcfg.NodeView
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
n, ok = b.nodeByAddr[ipp.Addr()]
|
n, ok = b.nodeByAddr[ipp.Addr()]
|
||||||
@ -808,16 +811,16 @@ func (b *LocalBackend) WhoIs(ipp netip.AddrPort) (n *tailcfg.Node, u tailcfg.Use
|
|||||||
ip, ok = b.e.WhoIsIPPort(ipp)
|
ip, ok = b.e.WhoIsIPPort(ipp)
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, u, false
|
return zero, u, false
|
||||||
}
|
}
|
||||||
n, ok = b.nodeByAddr[ip]
|
n, ok = b.nodeByAddr[ip]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, u, false
|
return zero, u, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
u, ok = b.netMap.UserProfiles[n.User]
|
u, ok = b.netMap.UserProfiles[n.User()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, u, false
|
return zero, u, false
|
||||||
}
|
}
|
||||||
return n, u, true
|
return n, u, true
|
||||||
}
|
}
|
||||||
@ -1114,13 +1117,14 @@ func setExitNodeID(prefs *ipn.Prefs, nm *netmap.NetworkMap) (prefsChanged bool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, peer := range nm.Peers {
|
for _, peer := range nm.Peers {
|
||||||
for _, addr := range peer.Addresses {
|
for i := range peer.Addresses().LenIter() {
|
||||||
|
addr := peer.Addresses().At(i)
|
||||||
if !addr.IsSingleIP() || addr.Addr() != prefs.ExitNodeIP {
|
if !addr.IsSingleIP() || addr.Addr() != prefs.ExitNodeIP {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Found the node being referenced, upgrade prefs to
|
// Found the node being referenced, upgrade prefs to
|
||||||
// reference it directly for next time.
|
// reference it directly for next time.
|
||||||
prefs.ExitNodeID = peer.StableID
|
prefs.ExitNodeID = peer.StableID()
|
||||||
prefs.ExitNodeIP = netip.Addr{}
|
prefs.ExitNodeIP = netip.Addr{}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -1597,16 +1601,16 @@ func (b *LocalBackend) updateFilterLocked(netMap *netmap.NetworkMap, prefs ipn.P
|
|||||||
//
|
//
|
||||||
// If this reports true, the packet filter is invalid (the server is either broken
|
// If this reports true, the packet filter is invalid (the server is either broken
|
||||||
// or malicious) and should be ignored for safety.
|
// or malicious) and should be ignored for safety.
|
||||||
func packetFilterPermitsUnlockedNodes(peers []*tailcfg.Node, packetFilter []filter.Match) bool {
|
func packetFilterPermitsUnlockedNodes(peers []tailcfg.NodeView, packetFilter []filter.Match) bool {
|
||||||
var b netipx.IPSetBuilder
|
var b netipx.IPSetBuilder
|
||||||
var numUnlocked int
|
var numUnlocked int
|
||||||
for _, p := range peers {
|
for _, p := range peers {
|
||||||
if !p.UnsignedPeerAPIOnly {
|
if !p.UnsignedPeerAPIOnly() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
numUnlocked++
|
numUnlocked++
|
||||||
for _, a := range p.AllowedIPs { // not only addresses!
|
for i := range p.AllowedIPs().LenIter() { // not only addresses!
|
||||||
b.AddPrefix(a)
|
b.AddPrefix(p.AllowedIPs().At(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if numUnlocked == 0 {
|
if numUnlocked == 0 {
|
||||||
@ -1764,11 +1768,11 @@ func shrinkDefaultRoute(route netip.Prefix, localInterfaceRoutes *netipx.IPSet,
|
|||||||
|
|
||||||
// dnsCIDRsEqual determines whether two CIDR lists are equal
|
// dnsCIDRsEqual determines whether two CIDR lists are equal
|
||||||
// for DNS map construction purposes (that is, only the first entry counts).
|
// for DNS map construction purposes (that is, only the first entry counts).
|
||||||
func dnsCIDRsEqual(newAddr, oldAddr []netip.Prefix) bool {
|
func dnsCIDRsEqual(newAddr, oldAddr views.Slice[netip.Prefix]) bool {
|
||||||
if len(newAddr) != len(oldAddr) {
|
if newAddr.Len() != oldAddr.Len() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if len(newAddr) == 0 || newAddr[0] == oldAddr[0] {
|
if newAddr.Len() == 0 || newAddr.At(0) == oldAddr.At(0) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -1792,16 +1796,16 @@ func dnsMapsEqual(new, old *netmap.NetworkMap) bool {
|
|||||||
if new.Name != old.Name {
|
if new.Name != old.Name {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !dnsCIDRsEqual(new.Addresses, old.Addresses) {
|
if !dnsCIDRsEqual(views.SliceOf(new.Addresses), views.SliceOf(old.Addresses)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, newPeer := range new.Peers {
|
for i, newPeer := range new.Peers {
|
||||||
oldPeer := old.Peers[i]
|
oldPeer := old.Peers[i]
|
||||||
if newPeer.Name != oldPeer.Name {
|
if newPeer.Name() != oldPeer.Name() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !dnsCIDRsEqual(newPeer.Addresses, oldPeer.Addresses) {
|
if !dnsCIDRsEqual(newPeer.Addresses(), oldPeer.Addresses()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2418,8 +2422,8 @@ func (b *LocalBackend) Ping(ctx context.Context, ip netip.Addr, pingType tailcfg
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
pr.Err = err.Error()
|
pr.Err = err.Error()
|
||||||
}
|
}
|
||||||
if node != nil {
|
if node.Valid() {
|
||||||
pr.NodeName = node.Name
|
pr.NodeName = node.Name()
|
||||||
}
|
}
|
||||||
return pr, nil
|
return pr, nil
|
||||||
}
|
}
|
||||||
@ -2438,36 +2442,37 @@ func (b *LocalBackend) Ping(ctx context.Context, ip netip.Addr, pingType tailcfg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) pingPeerAPI(ctx context.Context, ip netip.Addr) (peer *tailcfg.Node, peerBase string, err error) {
|
func (b *LocalBackend) pingPeerAPI(ctx context.Context, ip netip.Addr) (peer tailcfg.NodeView, peerBase string, err error) {
|
||||||
|
var zero tailcfg.NodeView
|
||||||
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
nm := b.NetMap()
|
nm := b.NetMap()
|
||||||
if nm == nil {
|
if nm == nil {
|
||||||
return nil, "", errors.New("no netmap")
|
return zero, "", errors.New("no netmap")
|
||||||
}
|
}
|
||||||
peer, ok := nm.PeerByTailscaleIP(ip)
|
peer, ok := nm.PeerByTailscaleIP(ip)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, "", fmt.Errorf("no peer found with Tailscale IP %v", ip)
|
return zero, "", fmt.Errorf("no peer found with Tailscale IP %v", ip)
|
||||||
}
|
}
|
||||||
if peer.Expired {
|
if peer.Expired() {
|
||||||
return nil, "", errors.New("peer's node key has expired")
|
return zero, "", errors.New("peer's node key has expired")
|
||||||
}
|
}
|
||||||
base := peerAPIBase(nm, peer)
|
base := peerAPIBase(nm, peer)
|
||||||
if base == "" {
|
if base == "" {
|
||||||
return nil, "", fmt.Errorf("no PeerAPI base found for peer %v (%v)", peer.ID, ip)
|
return zero, "", fmt.Errorf("no PeerAPI base found for peer %v (%v)", peer.ID(), ip)
|
||||||
}
|
}
|
||||||
outReq, err := http.NewRequestWithContext(ctx, "HEAD", base, nil)
|
outReq, err := http.NewRequestWithContext(ctx, "HEAD", base, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return zero, "", err
|
||||||
}
|
}
|
||||||
tr := b.Dialer().PeerAPITransport()
|
tr := b.Dialer().PeerAPITransport()
|
||||||
res, err := tr.RoundTrip(outReq)
|
res, err := tr.RoundTrip(outReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return zero, "", err
|
||||||
}
|
}
|
||||||
defer res.Body.Close() // but unnecessary on HEAD responses
|
defer res.Body.Close() // but unnecessary on HEAD responses
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
return nil, "", fmt.Errorf("HTTP status %v", res.Status)
|
return zero, "", fmt.Errorf("HTTP status %v", res.Status)
|
||||||
}
|
}
|
||||||
return peer, base, nil
|
return peer, base, nil
|
||||||
}
|
}
|
||||||
@ -3098,17 +3103,24 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs ipn.PrefsView, logf logger.
|
|||||||
// isn't configured to make MagicDNS resolution truly
|
// isn't configured to make MagicDNS resolution truly
|
||||||
// magic. Details in
|
// magic. Details in
|
||||||
// https://github.com/tailscale/tailscale/issues/1886.
|
// https://github.com/tailscale/tailscale/issues/1886.
|
||||||
set := func(name string, addrs []netip.Prefix) {
|
set := func(name string, addrs views.Slice[netip.Prefix]) {
|
||||||
if len(addrs) == 0 || name == "" {
|
if addrs.Len() == 0 || name == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fqdn, err := dnsname.ToFQDN(name)
|
fqdn, err := dnsname.ToFQDN(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return // TODO: propagate error?
|
return // TODO: propagate error?
|
||||||
}
|
}
|
||||||
have4 := slices.ContainsFunc(addrs, tsaddr.PrefixIs4)
|
var have4 bool
|
||||||
|
for i := range addrs.LenIter() {
|
||||||
|
if addrs.At(i).Addr().Is4() {
|
||||||
|
have4 = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
var ips []netip.Addr
|
var ips []netip.Addr
|
||||||
for _, addr := range addrs {
|
for i := range addrs.LenIter() {
|
||||||
|
addr := addrs.At(i)
|
||||||
if selfV6Only {
|
if selfV6Only {
|
||||||
if addr.Addr().Is6() {
|
if addr.Addr().Is6() {
|
||||||
ips = append(ips, addr.Addr())
|
ips = append(ips, addr.Addr())
|
||||||
@ -3130,9 +3142,9 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, prefs ipn.PrefsView, logf logger.
|
|||||||
}
|
}
|
||||||
dcfg.Hosts[fqdn] = ips
|
dcfg.Hosts[fqdn] = ips
|
||||||
}
|
}
|
||||||
set(nm.Name, nm.Addresses)
|
set(nm.Name, views.SliceOf(nm.Addresses))
|
||||||
for _, peer := range nm.Peers {
|
for _, peer := range nm.Peers {
|
||||||
set(peer.Name, peer.Addresses)
|
set(peer.Name(), peer.Addresses())
|
||||||
}
|
}
|
||||||
for _, rec := range nm.DNS.ExtraRecords {
|
for _, rec := range nm.DNS.ExtraRecords {
|
||||||
switch rec.Type {
|
switch rec.Type {
|
||||||
@ -3995,28 +4007,28 @@ func (b *LocalBackend) setNetMapLocked(nm *netmap.NetworkMap) {
|
|||||||
|
|
||||||
// Update the nodeByAddr index.
|
// Update the nodeByAddr index.
|
||||||
if b.nodeByAddr == nil {
|
if b.nodeByAddr == nil {
|
||||||
b.nodeByAddr = map[netip.Addr]*tailcfg.Node{}
|
b.nodeByAddr = map[netip.Addr]tailcfg.NodeView{}
|
||||||
}
|
}
|
||||||
// First pass, mark everything unwanted.
|
// First pass, mark everything unwanted.
|
||||||
for k := range b.nodeByAddr {
|
for k := range b.nodeByAddr {
|
||||||
b.nodeByAddr[k] = nil
|
b.nodeByAddr[k] = tailcfg.NodeView{}
|
||||||
}
|
}
|
||||||
addNode := func(n *tailcfg.Node) {
|
addNode := func(n tailcfg.NodeView) {
|
||||||
for _, ipp := range n.Addresses {
|
for i := range n.Addresses().LenIter() {
|
||||||
if ipp.IsSingleIP() {
|
if ipp := n.Addresses().At(i); ipp.IsSingleIP() {
|
||||||
b.nodeByAddr[ipp.Addr()] = n
|
b.nodeByAddr[ipp.Addr()] = n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if nm.SelfNode != nil {
|
if nm.SelfNode != nil {
|
||||||
addNode(nm.SelfNode)
|
addNode(nm.SelfNode.View())
|
||||||
}
|
}
|
||||||
for _, p := range nm.Peers {
|
for _, p := range nm.Peers {
|
||||||
addNode(p)
|
addNode(p)
|
||||||
}
|
}
|
||||||
// Third pass, actually delete the unwanted items.
|
// Third pass, actually delete the unwanted items.
|
||||||
for k, v := range b.nodeByAddr {
|
for k, v := range b.nodeByAddr {
|
||||||
if v == nil {
|
if !v.Valid() {
|
||||||
delete(b.nodeByAddr, k)
|
delete(b.nodeByAddr, k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4293,7 +4305,7 @@ func (b *LocalBackend) FileTargets() ([]*apitype.FileTarget, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ret = append(ret, &apitype.FileTarget{
|
ret = append(ret, &apitype.FileTarget{
|
||||||
Node: p,
|
Node: p.AsStruct(),
|
||||||
PeerAPIURL: peerAPI,
|
PeerAPIURL: peerAPI,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -4306,15 +4318,15 @@ func (b *LocalBackend) FileTargets() ([]*apitype.FileTarget, error) {
|
|||||||
// the netmap.
|
// the netmap.
|
||||||
//
|
//
|
||||||
// b.mu must be locked.
|
// b.mu must be locked.
|
||||||
func (b *LocalBackend) peerIsTaildropTargetLocked(p *tailcfg.Node) bool {
|
func (b *LocalBackend) peerIsTaildropTargetLocked(p tailcfg.NodeView) bool {
|
||||||
if b.netMap == nil || p == nil {
|
if b.netMap == nil || !p.Valid() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if b.netMap.User == p.User {
|
if b.netMap.User == p.User() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if len(p.Addresses) > 0 &&
|
if p.Addresses().Len() > 0 &&
|
||||||
b.peerHasCapLocked(p.Addresses[0].Addr(), tailcfg.PeerCapabilityFileSharingTarget) {
|
b.peerHasCapLocked(p.Addresses().At(0).Addr(), tailcfg.PeerCapabilityFileSharingTarget) {
|
||||||
// Explicitly noted in the netmap ACL caps as a target.
|
// Explicitly noted in the netmap ACL caps as a target.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -4374,9 +4386,9 @@ func (b *LocalBackend) registerIncomingFile(inf *incomingFile, active bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func peerAPIPorts(peer *tailcfg.Node) (p4, p6 uint16) {
|
func peerAPIPorts(peer tailcfg.NodeView) (p4, p6 uint16) {
|
||||||
svcs := peer.Hostinfo.Services()
|
svcs := peer.Hostinfo().Services()
|
||||||
for i, n := 0, svcs.Len(); i < n; i++ {
|
for i := range svcs.LenIter() {
|
||||||
s := svcs.At(i)
|
s := svcs.At(i)
|
||||||
switch s.Proto {
|
switch s.Proto {
|
||||||
case tailcfg.PeerAPI4:
|
case tailcfg.PeerAPI4:
|
||||||
@ -4402,8 +4414,8 @@ func peerAPIURL(ip netip.Addr, port uint16) string {
|
|||||||
// peerAPIBase returns the "http://ip:port" URL base to reach peer's peerAPI.
|
// peerAPIBase returns the "http://ip:port" URL base to reach peer's peerAPI.
|
||||||
// It returns the empty string if the peer doesn't support the peerapi
|
// It returns the empty string if the peer doesn't support the peerapi
|
||||||
// or there's no matching address family based on the netmap's own addresses.
|
// or there's no matching address family based on the netmap's own addresses.
|
||||||
func peerAPIBase(nm *netmap.NetworkMap, peer *tailcfg.Node) string {
|
func peerAPIBase(nm *netmap.NetworkMap, peer tailcfg.NodeView) string {
|
||||||
if nm == nil || peer == nil || !peer.Hostinfo.Valid() {
|
if nm == nil || !peer.Valid() || !peer.Hostinfo().Valid() {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4429,8 +4441,9 @@ func peerAPIBase(nm *netmap.NetworkMap, peer *tailcfg.Node) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeIP(n *tailcfg.Node, pred func(netip.Addr) bool) netip.Addr {
|
func nodeIP(n tailcfg.NodeView, pred func(netip.Addr) bool) netip.Addr {
|
||||||
for _, a := range n.Addresses {
|
for i := range n.Addresses().LenIter() {
|
||||||
|
a := n.Addresses().At(i)
|
||||||
if a.IsSingleIP() && pred(a.Addr()) {
|
if a.IsSingleIP() && pred(a.Addr()) {
|
||||||
return a.Addr()
|
return a.Addr()
|
||||||
}
|
}
|
||||||
@ -4540,15 +4553,15 @@ func exitNodeCanProxyDNS(nm *netmap.NetworkMap, exitNodeID tailcfg.StableNodeID)
|
|||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
for _, p := range nm.Peers {
|
for _, p := range nm.Peers {
|
||||||
if p.StableID == exitNodeID && peerCanProxyDNS(p) {
|
if p.StableID() == exitNodeID && peerCanProxyDNS(p) {
|
||||||
return peerAPIBase(nm, p) + "/dns-query", true
|
return peerAPIBase(nm, p) + "/dns-query", true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
func peerCanProxyDNS(p *tailcfg.Node) bool {
|
func peerCanProxyDNS(p tailcfg.NodeView) bool {
|
||||||
if p.Cap >= 26 {
|
if p.Cap() >= 26 {
|
||||||
// Actually added at 25
|
// Actually added at 25
|
||||||
// (https://github.com/tailscale/tailscale/blob/3ae6f898cfdb58fd0e30937147dd6ce28c6808dd/tailcfg/tailcfg.go#L51)
|
// (https://github.com/tailscale/tailscale/blob/3ae6f898cfdb58fd0e30937147dd6ce28c6808dd/tailcfg/tailcfg.go#L51)
|
||||||
// so anything >= 26 can do it.
|
// so anything >= 26 can do it.
|
||||||
@ -4556,10 +4569,9 @@ func peerCanProxyDNS(p *tailcfg.Node) bool {
|
|||||||
}
|
}
|
||||||
// If p.Cap is not populated (e.g. older control server), then do the old
|
// If p.Cap is not populated (e.g. older control server), then do the old
|
||||||
// thing of searching through services.
|
// thing of searching through services.
|
||||||
services := p.Hostinfo.Services()
|
services := p.Hostinfo().Services()
|
||||||
for i, n := 0, services.Len(); i < n; i++ {
|
for i := range services.LenIter() {
|
||||||
s := services.At(i)
|
if s := services.At(i); s.Proto == tailcfg.PeerAPIDNS && s.Port >= 1 {
|
||||||
if s.Proto == tailcfg.PeerAPIDNS && s.Port >= 1 {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,46 +87,46 @@ func TestNetworkMapCompare(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Peers identical",
|
"Peers identical",
|
||||||
&netmap.NetworkMap{Peers: []*tailcfg.Node{}},
|
&netmap.NetworkMap{Peers: nodeViews([]*tailcfg.Node{})},
|
||||||
&netmap.NetworkMap{Peers: []*tailcfg.Node{}},
|
&netmap.NetworkMap{Peers: nodeViews([]*tailcfg.Node{})},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Peer list length",
|
"Peer list length",
|
||||||
// length of Peers list differs
|
// length of Peers list differs
|
||||||
&netmap.NetworkMap{Peers: []*tailcfg.Node{{}}},
|
&netmap.NetworkMap{Peers: nodeViews([]*tailcfg.Node{{}})},
|
||||||
&netmap.NetworkMap{Peers: []*tailcfg.Node{}},
|
&netmap.NetworkMap{Peers: nodeViews([]*tailcfg.Node{})},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Node names identical",
|
"Node names identical",
|
||||||
&netmap.NetworkMap{Peers: []*tailcfg.Node{{Name: "A"}}},
|
&netmap.NetworkMap{Peers: nodeViews([]*tailcfg.Node{{Name: "A"}})},
|
||||||
&netmap.NetworkMap{Peers: []*tailcfg.Node{{Name: "A"}}},
|
&netmap.NetworkMap{Peers: nodeViews([]*tailcfg.Node{{Name: "A"}})},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Node names differ",
|
"Node names differ",
|
||||||
&netmap.NetworkMap{Peers: []*tailcfg.Node{{Name: "A"}}},
|
&netmap.NetworkMap{Peers: nodeViews([]*tailcfg.Node{{Name: "A"}})},
|
||||||
&netmap.NetworkMap{Peers: []*tailcfg.Node{{Name: "B"}}},
|
&netmap.NetworkMap{Peers: nodeViews([]*tailcfg.Node{{Name: "B"}})},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Node lists identical",
|
"Node lists identical",
|
||||||
&netmap.NetworkMap{Peers: []*tailcfg.Node{node1, node1}},
|
&netmap.NetworkMap{Peers: nodeViews([]*tailcfg.Node{node1, node1})},
|
||||||
&netmap.NetworkMap{Peers: []*tailcfg.Node{node1, node1}},
|
&netmap.NetworkMap{Peers: nodeViews([]*tailcfg.Node{node1, node1})},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Node lists differ",
|
"Node lists differ",
|
||||||
&netmap.NetworkMap{Peers: []*tailcfg.Node{node1, node1}},
|
&netmap.NetworkMap{Peers: nodeViews([]*tailcfg.Node{node1, node1})},
|
||||||
&netmap.NetworkMap{Peers: []*tailcfg.Node{node1, node2}},
|
&netmap.NetworkMap{Peers: nodeViews([]*tailcfg.Node{node1, node2})},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Node Users differ",
|
"Node Users differ",
|
||||||
// User field is not checked.
|
// User field is not checked.
|
||||||
&netmap.NetworkMap{Peers: []*tailcfg.Node{{User: 0}}},
|
&netmap.NetworkMap{Peers: nodeViews([]*tailcfg.Node{{User: 0}})},
|
||||||
&netmap.NetworkMap{Peers: []*tailcfg.Node{{User: 1}}},
|
&netmap.NetworkMap{Peers: nodeViews([]*tailcfg.Node{{User: 1}})},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -483,7 +483,7 @@ func TestPeerAPIBase(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got := peerAPIBase(tt.nm, tt.peer)
|
got := peerAPIBase(tt.nm, tt.peer.View())
|
||||||
if got != tt.want {
|
if got != tt.want {
|
||||||
t.Errorf("got %q; want %q", got, tt.want)
|
t.Errorf("got %q; want %q", got, tt.want)
|
||||||
}
|
}
|
||||||
@ -758,7 +758,7 @@ func TestPacketFilterPermitsUnlockedNodes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if got := packetFilterPermitsUnlockedNodes(tt.peers, tt.filter); got != tt.want {
|
if got := packetFilterPermitsUnlockedNodes(nodeViews(tt.peers), tt.filter); got != tt.want {
|
||||||
t.Errorf("got %v, want %v", got, tt.want)
|
t.Errorf("got %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -69,15 +69,16 @@ func (b *LocalBackend) tkaFilterNetmapLocked(nm *netmap.NetworkMap) {
|
|||||||
|
|
||||||
var toDelete map[int]bool // peer index => true
|
var toDelete map[int]bool // peer index => true
|
||||||
for i, p := range nm.Peers {
|
for i, p := range nm.Peers {
|
||||||
if p.UnsignedPeerAPIOnly {
|
if p.UnsignedPeerAPIOnly() {
|
||||||
// Not subject to tailnet lock.
|
// Not subject to tailnet lock.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if len(p.KeySignature) == 0 {
|
keySig := tkatype.MarshaledSignature(p.KeySignature().StringCopy()) // TODO(bradfitz,maisem): this is unfortunate. Change tkatype.MarshaledSignature to a string for viewer?
|
||||||
|
if len(keySig) == 0 {
|
||||||
b.logf("Network lock is dropping peer %v(%v) due to missing signature", p.ID, p.StableID)
|
b.logf("Network lock is dropping peer %v(%v) due to missing signature", p.ID, p.StableID)
|
||||||
mak.Set(&toDelete, i, true)
|
mak.Set(&toDelete, i, true)
|
||||||
} else {
|
} else {
|
||||||
if err := b.tka.authority.NodeKeyAuthorized(p.Key, p.KeySignature); err != nil {
|
if err := b.tka.authority.NodeKeyAuthorized(p.Key(), keySig); err != nil {
|
||||||
b.logf("Network lock is dropping peer %v(%v) due to failed signature check: %v", p.ID, p.StableID, err)
|
b.logf("Network lock is dropping peer %v(%v) due to failed signature check: %v", p.ID, p.StableID, err)
|
||||||
mak.Set(&toDelete, i, true)
|
mak.Set(&toDelete, i, true)
|
||||||
}
|
}
|
||||||
@ -86,7 +87,7 @@ func (b *LocalBackend) tkaFilterNetmapLocked(nm *netmap.NetworkMap) {
|
|||||||
|
|
||||||
// nm.Peers is ordered, so deletion must be order-preserving.
|
// nm.Peers is ordered, so deletion must be order-preserving.
|
||||||
if len(toDelete) > 0 {
|
if len(toDelete) > 0 {
|
||||||
peers := make([]*tailcfg.Node, 0, len(nm.Peers))
|
peers := make([]tailcfg.NodeView, 0, len(nm.Peers))
|
||||||
filtered := make([]ipnstate.TKAFilteredPeer, 0, len(toDelete))
|
filtered := make([]ipnstate.TKAFilteredPeer, 0, len(toDelete))
|
||||||
for i, p := range nm.Peers {
|
for i, p := range nm.Peers {
|
||||||
if !toDelete[i] {
|
if !toDelete[i] {
|
||||||
@ -94,13 +95,14 @@ func (b *LocalBackend) tkaFilterNetmapLocked(nm *netmap.NetworkMap) {
|
|||||||
} else {
|
} else {
|
||||||
// Record information about the node we filtered out.
|
// Record information about the node we filtered out.
|
||||||
fp := ipnstate.TKAFilteredPeer{
|
fp := ipnstate.TKAFilteredPeer{
|
||||||
Name: p.Name,
|
Name: p.Name(),
|
||||||
ID: p.ID,
|
ID: p.ID(),
|
||||||
StableID: p.StableID,
|
StableID: p.StableID(),
|
||||||
TailscaleIPs: make([]netip.Addr, len(p.Addresses)),
|
TailscaleIPs: make([]netip.Addr, p.Addresses().Len()),
|
||||||
NodeKey: p.Key,
|
NodeKey: p.Key(),
|
||||||
}
|
}
|
||||||
for i, addr := range p.Addresses {
|
for i := range p.Addresses().LenIter() {
|
||||||
|
addr := p.Addresses().At(i)
|
||||||
if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.Addr()) {
|
if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.Addr()) {
|
||||||
fp.TailscaleIPs[i] = addr.Addr()
|
fp.TailscaleIPs[i] = addr.Addr()
|
||||||
}
|
}
|
||||||
|
@ -558,26 +558,26 @@ func TestTKAFilterNetmap(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
nm := netmap.NetworkMap{
|
nm := &netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{ID: 1, Key: n1.Public(), KeySignature: n1GoodSig.Serialize()},
|
{ID: 1, Key: n1.Public(), KeySignature: n1GoodSig.Serialize()},
|
||||||
{ID: 2, Key: n2.Public(), KeySignature: nil}, // missing sig
|
{ID: 2, Key: n2.Public(), KeySignature: nil}, // missing sig
|
||||||
{ID: 3, Key: n3.Public(), KeySignature: n1GoodSig.Serialize()}, // someone elses sig
|
{ID: 3, Key: n3.Public(), KeySignature: n1GoodSig.Serialize()}, // someone elses sig
|
||||||
{ID: 4, Key: n4.Public(), KeySignature: n4Sig.Serialize()}, // messed-up signature
|
{ID: 4, Key: n4.Public(), KeySignature: n4Sig.Serialize()}, // messed-up signature
|
||||||
{ID: 5, Key: n5.Public(), KeySignature: n5GoodSig.Serialize()},
|
{ID: 5, Key: n5.Public(), KeySignature: n5GoodSig.Serialize()},
|
||||||
},
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
b := &LocalBackend{
|
b := &LocalBackend{
|
||||||
logf: t.Logf,
|
logf: t.Logf,
|
||||||
tka: &tkaState{authority: authority},
|
tka: &tkaState{authority: authority},
|
||||||
}
|
}
|
||||||
b.tkaFilterNetmapLocked(&nm)
|
b.tkaFilterNetmapLocked(nm)
|
||||||
|
|
||||||
want := []*tailcfg.Node{
|
want := nodeViews([]*tailcfg.Node{
|
||||||
{ID: 1, Key: n1.Public(), KeySignature: n1GoodSig.Serialize()},
|
{ID: 1, Key: n1.Public(), KeySignature: n1GoodSig.Serialize()},
|
||||||
{ID: 5, Key: n5.Public(), KeySignature: n5GoodSig.Serialize()},
|
{ID: 5, Key: n5.Public(), KeySignature: n5GoodSig.Serialize()},
|
||||||
}
|
})
|
||||||
nodePubComparer := cmp.Comparer(func(x, y key.NodePublic) bool {
|
nodePubComparer := cmp.Comparer(func(x, y key.NodePublic) bool {
|
||||||
return x.Raw32() == y.Raw32()
|
return x.Raw32() == y.Raw32()
|
||||||
})
|
})
|
||||||
|
@ -576,7 +576,7 @@ func (pln *peerAPIListener) ServeConn(src netip.AddrPort, c net.Conn) {
|
|||||||
}
|
}
|
||||||
h := &peerAPIHandler{
|
h := &peerAPIHandler{
|
||||||
ps: pln.ps,
|
ps: pln.ps,
|
||||||
isSelf: nm.SelfNode.User == peerNode.User,
|
isSelf: nm.SelfNode.User == peerNode.User(),
|
||||||
remoteAddr: src,
|
remoteAddr: src,
|
||||||
selfNode: nm.SelfNode,
|
selfNode: nm.SelfNode,
|
||||||
peerNode: peerNode,
|
peerNode: peerNode,
|
||||||
@ -597,7 +597,7 @@ type peerAPIHandler struct {
|
|||||||
remoteAddr netip.AddrPort
|
remoteAddr netip.AddrPort
|
||||||
isSelf bool // whether peerNode is owned by same user as this node
|
isSelf bool // whether peerNode is owned by same user as this node
|
||||||
selfNode *tailcfg.Node // this node; always non-nil
|
selfNode *tailcfg.Node // this node; always non-nil
|
||||||
peerNode *tailcfg.Node // peerNode is who's making the request
|
peerNode tailcfg.NodeView // peerNode is who's making the request
|
||||||
peerUser tailcfg.UserProfile // profile of peerNode
|
peerUser tailcfg.UserProfile // profile of peerNode
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -608,8 +608,8 @@ func (h *peerAPIHandler) logf(format string, a ...any) {
|
|||||||
// isAddressValid reports whether addr is a valid destination address for this
|
// isAddressValid reports whether addr is a valid destination address for this
|
||||||
// node originating from the peer.
|
// node originating from the peer.
|
||||||
func (h *peerAPIHandler) isAddressValid(addr netip.Addr) bool {
|
func (h *peerAPIHandler) isAddressValid(addr netip.Addr) bool {
|
||||||
if h.peerNode.SelfNodeV4MasqAddrForThisPeer != nil {
|
if v := h.peerNode.SelfNodeV4MasqAddrForThisPeer(); v != nil {
|
||||||
return *h.peerNode.SelfNodeV4MasqAddrForThisPeer == addr
|
return *v == addr
|
||||||
}
|
}
|
||||||
pfx := netip.PrefixFrom(addr, addr.BitLen())
|
pfx := netip.PrefixFrom(addr, addr.BitLen())
|
||||||
return slices.Contains(h.selfNode.Addresses, pfx)
|
return slices.Contains(h.selfNode.Addresses, pfx)
|
||||||
@ -733,7 +733,7 @@ func (h *peerAPIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
<body>
|
<body>
|
||||||
<h1>Hello, %s (%v)</h1>
|
<h1>Hello, %s (%v)</h1>
|
||||||
This is my Tailscale device. Your device is %v.
|
This is my Tailscale device. Your device is %v.
|
||||||
`, html.EscapeString(who), h.remoteAddr.Addr(), html.EscapeString(h.peerNode.ComputedName))
|
`, html.EscapeString(who), h.remoteAddr.Addr(), html.EscapeString(h.peerNode.ComputedName()))
|
||||||
|
|
||||||
if h.isSelf {
|
if h.isSelf {
|
||||||
fmt.Fprintf(w, "<p>You are the owner of this node.\n")
|
fmt.Fprintf(w, "<p>You are the owner of this node.\n")
|
||||||
@ -1024,7 +1024,7 @@ func (f *incomingFile) PartialFile() ipn.PartialFile {
|
|||||||
|
|
||||||
// canPutFile reports whether h can put a file ("Taildrop") to this node.
|
// canPutFile reports whether h can put a file ("Taildrop") to this node.
|
||||||
func (h *peerAPIHandler) canPutFile() bool {
|
func (h *peerAPIHandler) canPutFile() bool {
|
||||||
if h.peerNode.UnsignedPeerAPIOnly {
|
if h.peerNode.UnsignedPeerAPIOnly() {
|
||||||
// Unsigned peers can't send files.
|
// Unsigned peers can't send files.
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -1038,7 +1038,7 @@ func (h *peerAPIHandler) canDebug() bool {
|
|||||||
// This node does not expose debug info.
|
// This node does not expose debug info.
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if h.peerNode.UnsignedPeerAPIOnly {
|
if h.peerNode.UnsignedPeerAPIOnly() {
|
||||||
// Unsigned peers can't debug.
|
// Unsigned peers can't debug.
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -1047,7 +1047,7 @@ func (h *peerAPIHandler) canDebug() bool {
|
|||||||
|
|
||||||
// canWakeOnLAN reports whether h can send a Wake-on-LAN packet from this node.
|
// canWakeOnLAN reports whether h can send a Wake-on-LAN packet from this node.
|
||||||
func (h *peerAPIHandler) canWakeOnLAN() bool {
|
func (h *peerAPIHandler) canWakeOnLAN() bool {
|
||||||
if h.peerNode.UnsignedPeerAPIOnly {
|
if h.peerNode.UnsignedPeerAPIOnly() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return h.isSelf || h.peerHasCap(tailcfg.PeerCapabilityWakeOnLAN)
|
return h.isSelf || h.peerHasCap(tailcfg.PeerCapabilityWakeOnLAN)
|
||||||
|
@ -462,9 +462,9 @@ func TestHandlePeerAPI(t *testing.T) {
|
|||||||
e.ph = &peerAPIHandler{
|
e.ph = &peerAPIHandler{
|
||||||
isSelf: tt.isSelf,
|
isSelf: tt.isSelf,
|
||||||
selfNode: selfNode,
|
selfNode: selfNode,
|
||||||
peerNode: &tailcfg.Node{
|
peerNode: (&tailcfg.Node{
|
||||||
ComputedName: "some-peer-name",
|
ComputedName: "some-peer-name",
|
||||||
},
|
}).View(),
|
||||||
ps: &peerAPIServer{
|
ps: &peerAPIServer{
|
||||||
b: lb,
|
b: lb,
|
||||||
},
|
},
|
||||||
@ -513,9 +513,9 @@ func TestFileDeleteRace(t *testing.T) {
|
|||||||
}
|
}
|
||||||
ph := &peerAPIHandler{
|
ph := &peerAPIHandler{
|
||||||
isSelf: true,
|
isSelf: true,
|
||||||
peerNode: &tailcfg.Node{
|
peerNode: (&tailcfg.Node{
|
||||||
ComputedName: "some-peer-name",
|
ComputedName: "some-peer-name",
|
||||||
},
|
}).View(),
|
||||||
selfNode: &tailcfg.Node{
|
selfNode: &tailcfg.Node{
|
||||||
Addresses: []netip.Prefix{netip.MustParsePrefix("100.100.100.101/32")},
|
Addresses: []netip.Prefix{netip.MustParsePrefix("100.100.100.101/32")},
|
||||||
},
|
},
|
||||||
|
@ -257,7 +257,7 @@ func (b *LocalBackend) ServeConfig() ipn.ServeConfigView {
|
|||||||
return b.serveConfig
|
return b.serveConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LocalBackend) HandleIngressTCPConn(ingressPeer *tailcfg.Node, target ipn.HostPort, srcAddr netip.AddrPort, getConnOrReset func() (net.Conn, bool), sendRST func()) {
|
func (b *LocalBackend) HandleIngressTCPConn(ingressPeer tailcfg.NodeView, target ipn.HostPort, srcAddr netip.AddrPort, getConnOrReset func() (net.Conn, bool), sendRST func()) {
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
sc := b.serveConfig
|
sc := b.serveConfig
|
||||||
b.mu.Unlock()
|
b.mu.Unlock()
|
||||||
|
@ -201,16 +201,16 @@ func TestServeHTTPProxy(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
b.nodeByAddr = map[netip.Addr]*tailcfg.Node{
|
b.nodeByAddr = map[netip.Addr]tailcfg.NodeView{
|
||||||
netip.MustParseAddr("100.150.151.152"): {
|
netip.MustParseAddr("100.150.151.152"): (&tailcfg.Node{
|
||||||
ComputedName: "some-peer",
|
ComputedName: "some-peer",
|
||||||
User: tailcfg.UserID(1),
|
User: tailcfg.UserID(1),
|
||||||
},
|
}).View(),
|
||||||
netip.MustParseAddr("100.150.151.153"): {
|
netip.MustParseAddr("100.150.151.153"): (&tailcfg.Node{
|
||||||
ComputedName: "some-tagged-peer",
|
ComputedName: "some-tagged-peer",
|
||||||
Tags: []string{"tag:server", "tag:test"},
|
Tags: []string{"tag:server", "tag:test"},
|
||||||
User: tailcfg.UserID(1),
|
User: tailcfg.UserID(1),
|
||||||
},
|
}).View(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start test serve endpoint.
|
// Start test serve endpoint.
|
||||||
|
@ -437,7 +437,7 @@ func (h *Handler) serveWhoIs(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
res := &apitype.WhoIsResponse{
|
res := &apitype.WhoIsResponse{
|
||||||
Node: n, // always non-nil per WhoIsResponse contract
|
Node: n.AsStruct(), // always non-nil per WhoIsResponse contract
|
||||||
UserProfile: &u, // always non-nil per WhoIsResponse contract
|
UserProfile: &u, // always non-nil per WhoIsResponse contract
|
||||||
CapMap: b.PeerCaps(ipp.Addr()),
|
CapMap: b.PeerCaps(ipp.Addr()),
|
||||||
}
|
}
|
||||||
|
@ -48,17 +48,18 @@ func dnsMapFromNetworkMap(nm *netmap.NetworkMap) dnsMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, p := range nm.Peers {
|
for _, p := range nm.Peers {
|
||||||
if p.Name == "" {
|
if p.Name() == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, a := range p.Addresses {
|
for i := range p.Addresses().LenIter() {
|
||||||
|
a := p.Addresses().At(i)
|
||||||
ip := a.Addr()
|
ip := a.Addr()
|
||||||
if ip.Is4() && !have4 {
|
if ip.Is4() && !have4 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ret[canonMapKey(p.Name)] = ip
|
ret[canonMapKey(p.Name())] = ip
|
||||||
if dnsname.HasSuffix(p.Name, suffix) {
|
if dnsname.HasSuffix(p.Name(), suffix) {
|
||||||
ret[canonMapKey(dnsname.TrimSuffix(p.Name, suffix))] = ip
|
ret[canonMapKey(dnsname.TrimSuffix(p.Name(), suffix))] = ip
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,14 @@
|
|||||||
"tailscale.com/types/netmap"
|
"tailscale.com/types/netmap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func nodeViews(v []*tailcfg.Node) []tailcfg.NodeView {
|
||||||
|
nv := make([]tailcfg.NodeView, len(v))
|
||||||
|
for i, n := range v {
|
||||||
|
nv[i] = n.View()
|
||||||
|
}
|
||||||
|
return nv
|
||||||
|
}
|
||||||
|
|
||||||
func TestDNSMapFromNetworkMap(t *testing.T) {
|
func TestDNSMapFromNetworkMap(t *testing.T) {
|
||||||
pfx := netip.MustParsePrefix
|
pfx := netip.MustParsePrefix
|
||||||
ip := netip.MustParseAddr
|
ip := netip.MustParseAddr
|
||||||
@ -42,20 +50,20 @@ func TestDNSMapFromNetworkMap(t *testing.T) {
|
|||||||
pfx("100.102.103.104/32"),
|
pfx("100.102.103.104/32"),
|
||||||
pfx("100::123/128"),
|
pfx("100::123/128"),
|
||||||
},
|
},
|
||||||
Peers: []*tailcfg.Node{
|
Peers: []tailcfg.NodeView{
|
||||||
{
|
(&tailcfg.Node{
|
||||||
Name: "a.tailnet",
|
Name: "a.tailnet",
|
||||||
Addresses: []netip.Prefix{
|
Addresses: []netip.Prefix{
|
||||||
pfx("100.0.0.201/32"),
|
pfx("100.0.0.201/32"),
|
||||||
pfx("100::201/128"),
|
pfx("100::201/128"),
|
||||||
},
|
},
|
||||||
},
|
}).View(),
|
||||||
{
|
(&tailcfg.Node{
|
||||||
Name: "b.tailnet",
|
Name: "b.tailnet",
|
||||||
Addresses: []netip.Prefix{
|
Addresses: []netip.Prefix{
|
||||||
pfx("100::202/128"),
|
pfx("100::202/128"),
|
||||||
},
|
},
|
||||||
},
|
}).View(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: dnsMap{
|
want: dnsMap{
|
||||||
@ -74,7 +82,7 @@ func TestDNSMapFromNetworkMap(t *testing.T) {
|
|||||||
Addresses: []netip.Prefix{
|
Addresses: []netip.Prefix{
|
||||||
pfx("100::123/128"),
|
pfx("100::123/128"),
|
||||||
},
|
},
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
Name: "a.tailnet",
|
Name: "a.tailnet",
|
||||||
Addresses: []netip.Prefix{
|
Addresses: []netip.Prefix{
|
||||||
@ -88,7 +96,7 @@ func TestDNSMapFromNetworkMap(t *testing.T) {
|
|||||||
pfx("100::202/128"),
|
pfx("100::202/128"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
want: dnsMap{
|
want: dnsMap{
|
||||||
"foo": ip("100::123"),
|
"foo": ip("100::123"),
|
||||||
|
@ -99,7 +99,7 @@ func (ss *sshSession) newIncubatorCommand() (cmd *exec.Cmd) {
|
|||||||
gids := strings.Join(ss.conn.userGroupIDs, ",")
|
gids := strings.Join(ss.conn.userGroupIDs, ",")
|
||||||
remoteUser := ci.uprof.LoginName
|
remoteUser := ci.uprof.LoginName
|
||||||
if ci.node.IsTagged() {
|
if ci.node.IsTagged() {
|
||||||
remoteUser = strings.Join(ci.node.Tags, ",")
|
remoteUser = strings.Join(ci.node.Tags().AsSlice(), ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
incubatorArgs := []string{
|
incubatorArgs := []string{
|
||||||
|
@ -64,7 +64,7 @@ type ipnLocalBackend interface {
|
|||||||
GetSSH_HostKeys() ([]gossh.Signer, error)
|
GetSSH_HostKeys() ([]gossh.Signer, error)
|
||||||
ShouldRunSSH() bool
|
ShouldRunSSH() bool
|
||||||
NetMap() *netmap.NetworkMap
|
NetMap() *netmap.NetworkMap
|
||||||
WhoIs(ipp netip.AddrPort) (n *tailcfg.Node, u tailcfg.UserProfile, ok bool)
|
WhoIs(ipp netip.AddrPort) (n tailcfg.NodeView, u tailcfg.UserProfile, ok bool)
|
||||||
DoNoiseRequest(req *http.Request) (*http.Response, error)
|
DoNoiseRequest(req *http.Request) (*http.Response, error)
|
||||||
Dialer() *tsdial.Dialer
|
Dialer() *tsdial.Dialer
|
||||||
TailscaleVarRoot() string
|
TailscaleVarRoot() string
|
||||||
@ -791,7 +791,7 @@ func (c *conn) expandDelegateURLLocked(actionURL string) string {
|
|||||||
}
|
}
|
||||||
return strings.NewReplacer(
|
return strings.NewReplacer(
|
||||||
"$SRC_NODE_IP", url.QueryEscape(ci.src.Addr().String()),
|
"$SRC_NODE_IP", url.QueryEscape(ci.src.Addr().String()),
|
||||||
"$SRC_NODE_ID", fmt.Sprint(int64(ci.node.ID)),
|
"$SRC_NODE_ID", fmt.Sprint(int64(ci.node.ID())),
|
||||||
"$DST_NODE_IP", url.QueryEscape(ci.dst.Addr().String()),
|
"$DST_NODE_IP", url.QueryEscape(ci.dst.Addr().String()),
|
||||||
"$DST_NODE_ID", dstNodeID,
|
"$DST_NODE_ID", dstNodeID,
|
||||||
"$SSH_USER", url.QueryEscape(ci.sshUser),
|
"$SSH_USER", url.QueryEscape(ci.sshUser),
|
||||||
@ -1220,7 +1220,7 @@ type sshConnInfo struct {
|
|||||||
dst netip.AddrPort
|
dst netip.AddrPort
|
||||||
|
|
||||||
// node is srcIP's node.
|
// node is srcIP's node.
|
||||||
node *tailcfg.Node
|
node tailcfg.NodeView
|
||||||
|
|
||||||
// uprof is node's UserProfile.
|
// uprof is node's UserProfile.
|
||||||
uprof tailcfg.UserProfile
|
uprof tailcfg.UserProfile
|
||||||
@ -1334,7 +1334,7 @@ func (c *conn) principalMatchesTailscaleIdentity(p *tailcfg.SSHPrincipal) bool {
|
|||||||
if p.Any {
|
if p.Any {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if !p.Node.IsZero() && ci.node != nil && p.Node == ci.node.StableID {
|
if !p.Node.IsZero() && ci.node.Valid() && p.Node == ci.node.StableID() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if p.NodeIP != "" {
|
if p.NodeIP != "" {
|
||||||
@ -1702,15 +1702,15 @@ func (ss *sshSession) startNewRecording() (_ *recording, err error) {
|
|||||||
},
|
},
|
||||||
SSHUser: ss.conn.info.sshUser,
|
SSHUser: ss.conn.info.sshUser,
|
||||||
LocalUser: ss.conn.localUser.Username,
|
LocalUser: ss.conn.localUser.Username,
|
||||||
SrcNode: strings.TrimSuffix(ss.conn.info.node.Name, "."),
|
SrcNode: strings.TrimSuffix(ss.conn.info.node.Name(), "."),
|
||||||
SrcNodeID: ss.conn.info.node.StableID,
|
SrcNodeID: ss.conn.info.node.StableID(),
|
||||||
ConnectionID: ss.conn.connID,
|
ConnectionID: ss.conn.connID,
|
||||||
}
|
}
|
||||||
if !ss.conn.info.node.IsTagged() {
|
if !ss.conn.info.node.IsTagged() {
|
||||||
ch.SrcNodeUser = ss.conn.info.uprof.LoginName
|
ch.SrcNodeUser = ss.conn.info.uprof.LoginName
|
||||||
ch.SrcNodeUserID = ss.conn.info.node.User
|
ch.SrcNodeUserID = ss.conn.info.node.User()
|
||||||
} else {
|
} else {
|
||||||
ch.SrcNodeTags = ss.conn.info.node.Tags
|
ch.SrcNodeTags = ss.conn.info.node.Tags().AsSlice()
|
||||||
}
|
}
|
||||||
j, err := json.Marshal(ch)
|
j, err := json.Marshal(ch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1738,7 +1738,7 @@ func (ss *sshSession) notifyControl(ctx context.Context, nodeKey key.NodePublic,
|
|||||||
ConnectionID: ss.conn.connID,
|
ConnectionID: ss.conn.connID,
|
||||||
CapVersion: tailcfg.CurrentCapabilityVersion,
|
CapVersion: tailcfg.CurrentCapabilityVersion,
|
||||||
NodeKey: nodeKey,
|
NodeKey: nodeKey,
|
||||||
SrcNode: ss.conn.info.node.ID,
|
SrcNode: ss.conn.info.node.ID(),
|
||||||
SSHUser: ss.conn.info.sshUser,
|
SSHUser: ss.conn.info.sshUser,
|
||||||
LocalUser: ss.conn.localUser.Username,
|
LocalUser: ss.conn.localUser.Username,
|
||||||
RecordingAttempts: attempts,
|
RecordingAttempts: attempts,
|
||||||
|
@ -177,7 +177,7 @@ func TestMatchRule(t *testing.T) {
|
|||||||
Principals: []*tailcfg.SSHPrincipal{{Node: "some-node-ID"}},
|
Principals: []*tailcfg.SSHPrincipal{{Node: "some-node-ID"}},
|
||||||
SSHUsers: map[string]string{"*": "ubuntu"},
|
SSHUsers: map[string]string{"*": "ubuntu"},
|
||||||
},
|
},
|
||||||
ci: &sshConnInfo{node: &tailcfg.Node{StableID: "some-node-ID"}},
|
ci: &sshConnInfo{node: (&tailcfg.Node{StableID: "some-node-ID"}).View()},
|
||||||
wantUser: "ubuntu",
|
wantUser: "ubuntu",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -283,11 +283,11 @@ func (ts *localState) NetMap() *netmap.NetworkMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *localState) WhoIs(ipp netip.AddrPort) (n *tailcfg.Node, u tailcfg.UserProfile, ok bool) {
|
func (ts *localState) WhoIs(ipp netip.AddrPort) (n tailcfg.NodeView, u tailcfg.UserProfile, ok bool) {
|
||||||
return &tailcfg.Node{
|
return (&tailcfg.Node{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
StableID: "peer-id",
|
StableID: "peer-id",
|
||||||
}, tailcfg.UserProfile{
|
}).View(), tailcfg.UserProfile{
|
||||||
LoginName: "peer",
|
LoginName: "peer",
|
||||||
}, true
|
}, true
|
||||||
|
|
||||||
@ -861,7 +861,7 @@ func TestSSH(t *testing.T) {
|
|||||||
sshUser: "test",
|
sshUser: "test",
|
||||||
src: netip.MustParseAddrPort("1.2.3.4:32342"),
|
src: netip.MustParseAddrPort("1.2.3.4:32342"),
|
||||||
dst: netip.MustParseAddrPort("1.2.3.5:22"),
|
dst: netip.MustParseAddrPort("1.2.3.5:22"),
|
||||||
node: &tailcfg.Node{},
|
node: (&tailcfg.Node{}).View(),
|
||||||
uprof: tailcfg.UserProfile{},
|
uprof: tailcfg.UserProfile{},
|
||||||
}
|
}
|
||||||
sc.action0 = &tailcfg.SSHAction{Accept: true}
|
sc.action0 = &tailcfg.SSHAction{Accept: true}
|
||||||
|
@ -388,6 +388,12 @@ func (n *Node) IsTagged() bool {
|
|||||||
return len(n.Tags) > 0
|
return len(n.Tags) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsTagged reports whether the node has any tags.
|
||||||
|
func (n NodeView) IsTagged() bool { return n.ж.IsTagged() }
|
||||||
|
|
||||||
|
// DisplayName wraps Node.DisplayName.
|
||||||
|
func (n NodeView) DisplayName(forOwner bool) string { return n.ж.DisplayName(forOwner) }
|
||||||
|
|
||||||
// InitDisplayNames computes and populates n's display name
|
// InitDisplayNames computes and populates n's display name
|
||||||
// fields: n.ComputedName, n.computedHostIfDifferent, and
|
// fields: n.ComputedName, n.computedHostIfDifferent, and
|
||||||
// n.ComputedNameWithHost.
|
// n.ComputedNameWithHost.
|
||||||
|
@ -34,7 +34,7 @@ type NetworkMap struct {
|
|||||||
Addresses []netip.Prefix // same as tailcfg.Node.Addresses (IP addresses of this Node directly)
|
Addresses []netip.Prefix // same as tailcfg.Node.Addresses (IP addresses of this Node directly)
|
||||||
MachineStatus tailcfg.MachineStatus
|
MachineStatus tailcfg.MachineStatus
|
||||||
MachineKey key.MachinePublic
|
MachineKey key.MachinePublic
|
||||||
Peers []*tailcfg.Node // sorted by Node.ID
|
Peers []tailcfg.NodeView // sorted by Node.ID
|
||||||
DNS tailcfg.DNSConfig
|
DNS tailcfg.DNSConfig
|
||||||
// TODO(maisem) : replace with View.
|
// TODO(maisem) : replace with View.
|
||||||
Hostinfo tailcfg.Hostinfo
|
Hostinfo tailcfg.Hostinfo
|
||||||
@ -84,7 +84,7 @@ type NetworkMap struct {
|
|||||||
// AnyPeersAdvertiseRoutes reports whether any peer is advertising non-exit node routes.
|
// AnyPeersAdvertiseRoutes reports whether any peer is advertising non-exit node routes.
|
||||||
func (nm *NetworkMap) AnyPeersAdvertiseRoutes() bool {
|
func (nm *NetworkMap) AnyPeersAdvertiseRoutes() bool {
|
||||||
for _, p := range nm.Peers {
|
for _, p := range nm.Peers {
|
||||||
if len(p.PrimaryRoutes) > 0 {
|
if p.PrimaryRoutes().Len() > 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,19 +94,21 @@ func (nm *NetworkMap) AnyPeersAdvertiseRoutes() bool {
|
|||||||
// PeerByTailscaleIP returns a peer's Node based on its Tailscale IP.
|
// PeerByTailscaleIP returns a peer's Node based on its Tailscale IP.
|
||||||
//
|
//
|
||||||
// If nm is nil or no peer is found, ok is false.
|
// If nm is nil or no peer is found, ok is false.
|
||||||
func (nm *NetworkMap) PeerByTailscaleIP(ip netip.Addr) (peer *tailcfg.Node, ok bool) {
|
func (nm *NetworkMap) PeerByTailscaleIP(ip netip.Addr) (peer tailcfg.NodeView, ok bool) {
|
||||||
// TODO(bradfitz):
|
// TODO(bradfitz):
|
||||||
if nm == nil {
|
if nm == nil {
|
||||||
return nil, false
|
return tailcfg.NodeView{}, false
|
||||||
}
|
}
|
||||||
for _, n := range nm.Peers {
|
for _, n := range nm.Peers {
|
||||||
for _, a := range n.Addresses {
|
ad := n.Addresses()
|
||||||
|
for i := 0; i < ad.Len(); i++ {
|
||||||
|
a := ad.At(i)
|
||||||
if a.Addr() == ip {
|
if a.Addr() == ip {
|
||||||
return n, true
|
return n, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, false
|
return tailcfg.NodeView{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// MagicDNSSuffix returns the domain's MagicDNS suffix (even if
|
// MagicDNSSuffix returns the domain's MagicDNS suffix (even if
|
||||||
@ -153,13 +155,13 @@ func (nm *NetworkMap) VeryConcise() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PeerWithStableID finds and returns the peer associated to the inputted StableNodeID.
|
// PeerWithStableID finds and returns the peer associated to the inputted StableNodeID.
|
||||||
func (nm *NetworkMap) PeerWithStableID(pid tailcfg.StableNodeID) (_ *tailcfg.Node, ok bool) {
|
func (nm *NetworkMap) PeerWithStableID(pid tailcfg.StableNodeID) (_ tailcfg.NodeView, ok bool) {
|
||||||
for _, p := range nm.Peers {
|
for _, p := range nm.Peers {
|
||||||
if p.StableID == pid {
|
if p.StableID() == pid {
|
||||||
return p, true
|
return p, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, false
|
return tailcfg.NodeView{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// printConciseHeader prints a concise header line representing nm to buf.
|
// printConciseHeader prints a concise header line representing nm to buf.
|
||||||
@ -203,15 +205,17 @@ func (a *NetworkMap) equalConciseHeader(b *NetworkMap) bool {
|
|||||||
//
|
//
|
||||||
// If this function is changed to access different fields of p, keep
|
// If this function is changed to access different fields of p, keep
|
||||||
// in nodeConciseEqual in sync.
|
// in nodeConciseEqual in sync.
|
||||||
func printPeerConcise(buf *strings.Builder, p *tailcfg.Node) {
|
func printPeerConcise(buf *strings.Builder, p tailcfg.NodeView) {
|
||||||
aip := make([]string, len(p.AllowedIPs))
|
aip := make([]string, p.AllowedIPs().Len())
|
||||||
for i, a := range p.AllowedIPs {
|
for i := range aip {
|
||||||
|
a := p.AllowedIPs().At(i)
|
||||||
s := strings.TrimSuffix(fmt.Sprint(a), "/32")
|
s := strings.TrimSuffix(fmt.Sprint(a), "/32")
|
||||||
aip[i] = s
|
aip[i] = s
|
||||||
}
|
}
|
||||||
|
|
||||||
ep := make([]string, len(p.Endpoints))
|
ep := make([]string, p.Endpoints().Len())
|
||||||
for i, e := range p.Endpoints {
|
for i := range ep {
|
||||||
|
e := p.Endpoints().At(i)
|
||||||
// Align vertically on the ':' between IP and port
|
// Align vertically on the ':' between IP and port
|
||||||
colon := strings.IndexByte(e, ':')
|
colon := strings.IndexByte(e, ':')
|
||||||
spaces := 0
|
spaces := 0
|
||||||
@ -222,21 +226,21 @@ func printPeerConcise(buf *strings.Builder, p *tailcfg.Node) {
|
|||||||
ep[i] = fmt.Sprintf("%21v", e+strings.Repeat(" ", spaces))
|
ep[i] = fmt.Sprintf("%21v", e+strings.Repeat(" ", spaces))
|
||||||
}
|
}
|
||||||
|
|
||||||
derp := p.DERP
|
derp := p.DERP()
|
||||||
const derpPrefix = "127.3.3.40:"
|
const derpPrefix = "127.3.3.40:"
|
||||||
if strings.HasPrefix(derp, derpPrefix) {
|
if strings.HasPrefix(derp, derpPrefix) {
|
||||||
derp = "D" + derp[len(derpPrefix):]
|
derp = "D" + derp[len(derpPrefix):]
|
||||||
}
|
}
|
||||||
var discoShort string
|
var discoShort string
|
||||||
if !p.DiscoKey.IsZero() {
|
if !p.DiscoKey().IsZero() {
|
||||||
discoShort = p.DiscoKey.ShortString() + " "
|
discoShort = p.DiscoKey().ShortString() + " "
|
||||||
}
|
}
|
||||||
|
|
||||||
// Most of the time, aip is just one element, so format the
|
// Most of the time, aip is just one element, so format the
|
||||||
// table to look good in that case. This will also make multi-
|
// table to look good in that case. This will also make multi-
|
||||||
// subnet nodes stand out visually.
|
// subnet nodes stand out visually.
|
||||||
fmt.Fprintf(buf, " %v %s%-2v %-15v : %v\n",
|
fmt.Fprintf(buf, " %v %s%-2v %-15v : %v\n",
|
||||||
p.Key.ShortString(),
|
p.Key().ShortString(),
|
||||||
discoShort,
|
discoShort,
|
||||||
derp,
|
derp,
|
||||||
strings.Join(aip, " "),
|
strings.Join(aip, " "),
|
||||||
@ -244,12 +248,12 @@ func printPeerConcise(buf *strings.Builder, p *tailcfg.Node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// nodeConciseEqual reports whether a and b are equal for the fields accessed by printPeerConcise.
|
// nodeConciseEqual reports whether a and b are equal for the fields accessed by printPeerConcise.
|
||||||
func nodeConciseEqual(a, b *tailcfg.Node) bool {
|
func nodeConciseEqual(a, b tailcfg.NodeView) bool {
|
||||||
return a.Key == b.Key &&
|
return a.Key() == b.Key() &&
|
||||||
a.DERP == b.DERP &&
|
a.DERP() == b.DERP() &&
|
||||||
a.DiscoKey == b.DiscoKey &&
|
a.DiscoKey() == b.DiscoKey() &&
|
||||||
eqCIDRsIgnoreNil(a.AllowedIPs, b.AllowedIPs) &&
|
eqViewsIgnoreNil(a.AllowedIPs(), b.AllowedIPs()) &&
|
||||||
eqStringsIgnoreNil(a.Endpoints, b.Endpoints)
|
eqViewsIgnoreNil(a.Endpoints(), b.Endpoints())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *NetworkMap) ConciseDiffFrom(a *NetworkMap) string {
|
func (b *NetworkMap) ConciseDiffFrom(a *NetworkMap) string {
|
||||||
@ -268,7 +272,7 @@ func (b *NetworkMap) ConciseDiffFrom(a *NetworkMap) string {
|
|||||||
for len(aps) > 0 && len(bps) > 0 {
|
for len(aps) > 0 && len(bps) > 0 {
|
||||||
pa, pb := aps[0], bps[0]
|
pa, pb := aps[0], bps[0]
|
||||||
switch {
|
switch {
|
||||||
case pa.ID == pb.ID:
|
case pa.ID() == pb.ID():
|
||||||
if !nodeConciseEqual(pa, pb) {
|
if !nodeConciseEqual(pa, pb) {
|
||||||
diff.WriteByte('-')
|
diff.WriteByte('-')
|
||||||
printPeerConcise(&diff, pa)
|
printPeerConcise(&diff, pa)
|
||||||
@ -276,12 +280,12 @@ func (b *NetworkMap) ConciseDiffFrom(a *NetworkMap) string {
|
|||||||
printPeerConcise(&diff, pb)
|
printPeerConcise(&diff, pb)
|
||||||
}
|
}
|
||||||
aps, bps = aps[1:], bps[1:]
|
aps, bps = aps[1:], bps[1:]
|
||||||
case pa.ID > pb.ID:
|
case pa.ID() > pb.ID():
|
||||||
// New peer in b.
|
// New peer in b.
|
||||||
diff.WriteByte('+')
|
diff.WriteByte('+')
|
||||||
printPeerConcise(&diff, pb)
|
printPeerConcise(&diff, pb)
|
||||||
bps = bps[1:]
|
bps = bps[1:]
|
||||||
case pb.ID > pa.ID:
|
case pb.ID() > pa.ID():
|
||||||
// Deleted peer in b.
|
// Deleted peer in b.
|
||||||
diff.WriteByte('-')
|
diff.WriteByte('-')
|
||||||
printPeerConcise(&diff, pa)
|
printPeerConcise(&diff, pa)
|
||||||
@ -316,28 +320,18 @@ func (nm *NetworkMap) JSON() string {
|
|||||||
AllowSubnetRoutes
|
AllowSubnetRoutes
|
||||||
)
|
)
|
||||||
|
|
||||||
// eqStringsIgnoreNil reports whether a and b have the same length and
|
// eqViewsIgnoreNil reports whether a and b have the same length and comparably
|
||||||
// contents, but ignore whether a or b are nil.
|
// equal values at each index. It's used for comparing views of slices and not
|
||||||
func eqStringsIgnoreNil(a, b []string) bool {
|
// caring about whether the slices are nil or not.
|
||||||
if len(a) != len(b) {
|
func eqViewsIgnoreNil[T comparable](a, b interface {
|
||||||
|
Len() int
|
||||||
|
At(int) T
|
||||||
|
}) bool {
|
||||||
|
if a.Len() != b.Len() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for i, v := range a {
|
for i, n := 0, a.Len(); i < n; i++ {
|
||||||
if v != b[i] {
|
if a.At(i) != b.At(i) {
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// eqCIDRsIgnoreNil reports whether a and b have the same length and
|
|
||||||
// contents, but ignore whether a or b are nil.
|
|
||||||
func eqCIDRsIgnoreNil(a, b []netip.Prefix) bool {
|
|
||||||
if len(a) != len(b) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for i, v := range a {
|
|
||||||
if v != b[i] {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,14 @@ func testDiscoKey(hexPrefix string) (ret key.DiscoPublic) {
|
|||||||
return key.DiscoPublicFromRaw32(mem.B(bs[:]))
|
return key.DiscoPublicFromRaw32(mem.B(bs[:]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func nodeViews(v []*tailcfg.Node) []tailcfg.NodeView {
|
||||||
|
nv := make([]tailcfg.NodeView, len(v))
|
||||||
|
for i, n := range v {
|
||||||
|
nv[i] = n.View()
|
||||||
|
}
|
||||||
|
return nv
|
||||||
|
}
|
||||||
|
|
||||||
func TestNetworkMapConcise(t *testing.T) {
|
func TestNetworkMapConcise(t *testing.T) {
|
||||||
for _, tt := range []struct {
|
for _, tt := range []struct {
|
||||||
name string
|
name string
|
||||||
@ -44,7 +52,7 @@ func TestNetworkMapConcise(t *testing.T) {
|
|||||||
name: "basic",
|
name: "basic",
|
||||||
nm: &NetworkMap{
|
nm: &NetworkMap{
|
||||||
NodeKey: testNodeKey(1),
|
NodeKey: testNodeKey(1),
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
Key: testNodeKey(2),
|
Key: testNodeKey(2),
|
||||||
DERP: "127.3.3.40:2",
|
DERP: "127.3.3.40:2",
|
||||||
@ -55,7 +63,7 @@ func TestNetworkMapConcise(t *testing.T) {
|
|||||||
DERP: "127.3.3.40:4",
|
DERP: "127.3.3.40:4",
|
||||||
Endpoints: []string{"10.2.0.100:12", "10.1.0.100:12345"},
|
Endpoints: []string{"10.2.0.100:12", "10.1.0.100:12345"},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
want: "netmap: self: [AQEBA] auth=machine-unknown u=? []\n [AgICA] D2 : 192.168.0.100:12 192.168.0.100:12354\n [AwMDA] D4 : 10.2.0.100:12 10.1.0.100:12345\n",
|
want: "netmap: self: [AQEBA] auth=machine-unknown u=? []\n [AgICA] D2 : 192.168.0.100:12 192.168.0.100:12354\n [AwMDA] D4 : 10.2.0.100:12 10.1.0.100:12345\n",
|
||||||
},
|
},
|
||||||
@ -83,23 +91,23 @@ func TestConciseDiffFrom(t *testing.T) {
|
|||||||
name: "no_change",
|
name: "no_change",
|
||||||
a: &NetworkMap{
|
a: &NetworkMap{
|
||||||
NodeKey: testNodeKey(1),
|
NodeKey: testNodeKey(1),
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
Key: testNodeKey(2),
|
Key: testNodeKey(2),
|
||||||
DERP: "127.3.3.40:2",
|
DERP: "127.3.3.40:2",
|
||||||
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
|
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
b: &NetworkMap{
|
b: &NetworkMap{
|
||||||
NodeKey: testNodeKey(1),
|
NodeKey: testNodeKey(1),
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
Key: testNodeKey(2),
|
Key: testNodeKey(2),
|
||||||
DERP: "127.3.3.40:2",
|
DERP: "127.3.3.40:2",
|
||||||
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
|
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
want: "",
|
want: "",
|
||||||
},
|
},
|
||||||
@ -107,23 +115,23 @@ func TestConciseDiffFrom(t *testing.T) {
|
|||||||
name: "header_change",
|
name: "header_change",
|
||||||
a: &NetworkMap{
|
a: &NetworkMap{
|
||||||
NodeKey: testNodeKey(1),
|
NodeKey: testNodeKey(1),
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
Key: testNodeKey(2),
|
Key: testNodeKey(2),
|
||||||
DERP: "127.3.3.40:2",
|
DERP: "127.3.3.40:2",
|
||||||
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
|
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
b: &NetworkMap{
|
b: &NetworkMap{
|
||||||
NodeKey: testNodeKey(2),
|
NodeKey: testNodeKey(2),
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
Key: testNodeKey(2),
|
Key: testNodeKey(2),
|
||||||
DERP: "127.3.3.40:2",
|
DERP: "127.3.3.40:2",
|
||||||
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
|
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
want: "-netmap: self: [AQEBA] auth=machine-unknown u=? []\n+netmap: self: [AgICA] auth=machine-unknown u=? []\n",
|
want: "-netmap: self: [AQEBA] auth=machine-unknown u=? []\n+netmap: self: [AgICA] auth=machine-unknown u=? []\n",
|
||||||
},
|
},
|
||||||
@ -131,18 +139,18 @@ func TestConciseDiffFrom(t *testing.T) {
|
|||||||
name: "peer_add",
|
name: "peer_add",
|
||||||
a: &NetworkMap{
|
a: &NetworkMap{
|
||||||
NodeKey: testNodeKey(1),
|
NodeKey: testNodeKey(1),
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
Key: testNodeKey(2),
|
Key: testNodeKey(2),
|
||||||
DERP: "127.3.3.40:2",
|
DERP: "127.3.3.40:2",
|
||||||
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
|
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
b: &NetworkMap{
|
b: &NetworkMap{
|
||||||
NodeKey: testNodeKey(1),
|
NodeKey: testNodeKey(1),
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Key: testNodeKey(1),
|
Key: testNodeKey(1),
|
||||||
@ -161,7 +169,7 @@ func TestConciseDiffFrom(t *testing.T) {
|
|||||||
DERP: "127.3.3.40:3",
|
DERP: "127.3.3.40:3",
|
||||||
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
|
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
want: "+ [AQEBA] D1 : 192.168.0.100:12 192.168.0.100:12354\n+ [AwMDA] D3 : 192.168.0.100:12 192.168.0.100:12354\n",
|
want: "+ [AQEBA] D1 : 192.168.0.100:12 192.168.0.100:12354\n+ [AwMDA] D3 : 192.168.0.100:12 192.168.0.100:12354\n",
|
||||||
},
|
},
|
||||||
@ -169,7 +177,7 @@ func TestConciseDiffFrom(t *testing.T) {
|
|||||||
name: "peer_remove",
|
name: "peer_remove",
|
||||||
a: &NetworkMap{
|
a: &NetworkMap{
|
||||||
NodeKey: testNodeKey(1),
|
NodeKey: testNodeKey(1),
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Key: testNodeKey(1),
|
Key: testNodeKey(1),
|
||||||
@ -188,18 +196,18 @@ func TestConciseDiffFrom(t *testing.T) {
|
|||||||
DERP: "127.3.3.40:3",
|
DERP: "127.3.3.40:3",
|
||||||
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
|
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
b: &NetworkMap{
|
b: &NetworkMap{
|
||||||
NodeKey: testNodeKey(1),
|
NodeKey: testNodeKey(1),
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
Key: testNodeKey(2),
|
Key: testNodeKey(2),
|
||||||
DERP: "127.3.3.40:2",
|
DERP: "127.3.3.40:2",
|
||||||
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
|
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
want: "- [AQEBA] D1 : 192.168.0.100:12 192.168.0.100:12354\n- [AwMDA] D3 : 192.168.0.100:12 192.168.0.100:12354\n",
|
want: "- [AQEBA] D1 : 192.168.0.100:12 192.168.0.100:12354\n- [AwMDA] D3 : 192.168.0.100:12 192.168.0.100:12354\n",
|
||||||
},
|
},
|
||||||
@ -207,25 +215,25 @@ func TestConciseDiffFrom(t *testing.T) {
|
|||||||
name: "peer_port_change",
|
name: "peer_port_change",
|
||||||
a: &NetworkMap{
|
a: &NetworkMap{
|
||||||
NodeKey: testNodeKey(1),
|
NodeKey: testNodeKey(1),
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
Key: testNodeKey(2),
|
Key: testNodeKey(2),
|
||||||
DERP: "127.3.3.40:2",
|
DERP: "127.3.3.40:2",
|
||||||
Endpoints: []string{"192.168.0.100:12", "1.1.1.1:1"},
|
Endpoints: []string{"192.168.0.100:12", "1.1.1.1:1"},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
b: &NetworkMap{
|
b: &NetworkMap{
|
||||||
NodeKey: testNodeKey(1),
|
NodeKey: testNodeKey(1),
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
Key: testNodeKey(2),
|
Key: testNodeKey(2),
|
||||||
DERP: "127.3.3.40:2",
|
DERP: "127.3.3.40:2",
|
||||||
Endpoints: []string{"192.168.0.100:12", "1.1.1.1:2"},
|
Endpoints: []string{"192.168.0.100:12", "1.1.1.1:2"},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
want: "- [AgICA] D2 : 192.168.0.100:12 1.1.1.1:1 \n+ [AgICA] D2 : 192.168.0.100:12 1.1.1.1:2 \n",
|
want: "- [AgICA] D2 : 192.168.0.100:12 1.1.1.1:1 \n+ [AgICA] D2 : 192.168.0.100:12 1.1.1.1:2 \n",
|
||||||
},
|
},
|
||||||
@ -233,7 +241,7 @@ func TestConciseDiffFrom(t *testing.T) {
|
|||||||
name: "disco_key_only_change",
|
name: "disco_key_only_change",
|
||||||
a: &NetworkMap{
|
a: &NetworkMap{
|
||||||
NodeKey: testNodeKey(1),
|
NodeKey: testNodeKey(1),
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
Key: testNodeKey(2),
|
Key: testNodeKey(2),
|
||||||
@ -242,11 +250,11 @@ func TestConciseDiffFrom(t *testing.T) {
|
|||||||
DiscoKey: testDiscoKey("f00f00f00f"),
|
DiscoKey: testDiscoKey("f00f00f00f"),
|
||||||
AllowedIPs: []netip.Prefix{netip.PrefixFrom(netaddr.IPv4(100, 102, 103, 104), 32)},
|
AllowedIPs: []netip.Prefix{netip.PrefixFrom(netaddr.IPv4(100, 102, 103, 104), 32)},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
b: &NetworkMap{
|
b: &NetworkMap{
|
||||||
NodeKey: testNodeKey(1),
|
NodeKey: testNodeKey(1),
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
Key: testNodeKey(2),
|
Key: testNodeKey(2),
|
||||||
@ -255,7 +263,7 @@ func TestConciseDiffFrom(t *testing.T) {
|
|||||||
DiscoKey: testDiscoKey("ba4ba4ba4b"),
|
DiscoKey: testDiscoKey("ba4ba4ba4b"),
|
||||||
AllowedIPs: []netip.Prefix{netip.PrefixFrom(netaddr.IPv4(100, 102, 103, 104), 32)},
|
AllowedIPs: []netip.Prefix{netip.PrefixFrom(netaddr.IPv4(100, 102, 103, 104), 32)},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
want: "- [AgICA] d:f00f00f00f000000 D2 100.102.103.104 : 192.168.0.100:41641 1.1.1.1:41641\n+ [AgICA] d:ba4ba4ba4b000000 D2 100.102.103.104 : 192.168.0.100:41641 1.1.1.1:41641\n",
|
want: "- [AgICA] d:f00f00f00f000000 D2 100.102.103.104 : 192.168.0.100:41641 1.1.1.1:41641\n+ [AgICA] d:ba4ba4ba4b000000 D2 100.102.103.104 : 192.168.0.100:41641 1.1.1.1:41641\n",
|
||||||
},
|
},
|
||||||
|
@ -96,7 +96,7 @@ func setupWGTest(b *testing.B, logf logger.Logf, traf *TrafficGen, a1, a2 netip.
|
|||||||
eps = append(eps, ep.Addr.String())
|
eps = append(eps, ep.Addr.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
n := tailcfg.Node{
|
n := &tailcfg.Node{
|
||||||
ID: tailcfg.NodeID(0),
|
ID: tailcfg.NodeID(0),
|
||||||
Name: "n1",
|
Name: "n1",
|
||||||
Addresses: []netip.Prefix{a1},
|
Addresses: []netip.Prefix{a1},
|
||||||
@ -106,7 +106,7 @@ func setupWGTest(b *testing.B, logf logger.Logf, traf *TrafficGen, a1, a2 netip.
|
|||||||
e2.SetNetworkMap(&netmap.NetworkMap{
|
e2.SetNetworkMap(&netmap.NetworkMap{
|
||||||
NodeKey: k2.Public(),
|
NodeKey: k2.Public(),
|
||||||
PrivateKey: k2,
|
PrivateKey: k2,
|
||||||
Peers: []*tailcfg.Node{&n},
|
Peers: []tailcfg.NodeView{n.View()},
|
||||||
})
|
})
|
||||||
|
|
||||||
p := wgcfg.Peer{
|
p := wgcfg.Peer{
|
||||||
@ -133,7 +133,7 @@ func setupWGTest(b *testing.B, logf logger.Logf, traf *TrafficGen, a1, a2 netip.
|
|||||||
eps = append(eps, ep.Addr.String())
|
eps = append(eps, ep.Addr.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
n := tailcfg.Node{
|
n := &tailcfg.Node{
|
||||||
ID: tailcfg.NodeID(0),
|
ID: tailcfg.NodeID(0),
|
||||||
Name: "n2",
|
Name: "n2",
|
||||||
Addresses: []netip.Prefix{a2},
|
Addresses: []netip.Prefix{a2},
|
||||||
@ -143,7 +143,7 @@ func setupWGTest(b *testing.B, logf logger.Logf, traf *TrafficGen, a1, a2 netip.
|
|||||||
e1.SetNetworkMap(&netmap.NetworkMap{
|
e1.SetNetworkMap(&netmap.NetworkMap{
|
||||||
NodeKey: k1.Public(),
|
NodeKey: k1.Public(),
|
||||||
PrivateKey: k1,
|
PrivateKey: k1,
|
||||||
Peers: []*tailcfg.Node{&n},
|
Peers: []tailcfg.NodeView{n.View()},
|
||||||
})
|
})
|
||||||
|
|
||||||
p := wgcfg.Peer{
|
p := wgcfg.Peer{
|
||||||
|
@ -101,10 +101,10 @@ type kv struct {
|
|||||||
}
|
}
|
||||||
sort.Slice(ent, func(i, j int) bool { return ent[i].pub.Less(ent[j].pub) })
|
sort.Slice(ent, func(i, j int) bool { return ent[i].pub.Less(ent[j].pub) })
|
||||||
|
|
||||||
peers := map[key.NodePublic]*tailcfg.Node{}
|
peers := map[key.NodePublic]tailcfg.NodeView{}
|
||||||
if c.netMap != nil {
|
if c.netMap != nil {
|
||||||
for _, p := range c.netMap.Peers {
|
for _, p := range c.netMap.Peers {
|
||||||
peers[p.Key] = p
|
peers[p.Key()] = p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,15 +187,15 @@ func printEndpointHTML(w io.Writer, ep *endpoint) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func peerDebugName(p *tailcfg.Node) string {
|
func peerDebugName(p tailcfg.NodeView) string {
|
||||||
if p == nil {
|
if !p.Valid() {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
n := p.Name
|
n := p.Name()
|
||||||
if base, _, ok := strings.Cut(n, "."); ok {
|
if base, _, ok := strings.Cut(n, "."); ok {
|
||||||
return base
|
return base
|
||||||
}
|
}
|
||||||
return p.Hostinfo.Hostname()
|
return p.Hostinfo().Hostname()
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipPortLess(a, b netip.AddrPort) bool {
|
func ipPortLess(a, b netip.AddrPort) bool {
|
||||||
|
@ -725,15 +725,15 @@ func (de *endpoint) setLastPing(ipp netip.AddrPort, now mono.Time) {
|
|||||||
|
|
||||||
// updateFromNode updates the endpoint based on a tailcfg.Node from a NetMap
|
// updateFromNode updates the endpoint based on a tailcfg.Node from a NetMap
|
||||||
// update.
|
// update.
|
||||||
func (de *endpoint) updateFromNode(n *tailcfg.Node, heartbeatDisabled bool) {
|
func (de *endpoint) updateFromNode(n tailcfg.NodeView, heartbeatDisabled bool) {
|
||||||
if n == nil {
|
if !n.Valid() {
|
||||||
panic("nil node when updating endpoint")
|
panic("nil node when updating endpoint")
|
||||||
}
|
}
|
||||||
de.mu.Lock()
|
de.mu.Lock()
|
||||||
defer de.mu.Unlock()
|
defer de.mu.Unlock()
|
||||||
|
|
||||||
de.heartbeatDisabled = heartbeatDisabled
|
de.heartbeatDisabled = heartbeatDisabled
|
||||||
de.expired = n.Expired
|
de.expired = n.Expired()
|
||||||
|
|
||||||
epDisco := de.disco.Load()
|
epDisco := de.disco.Load()
|
||||||
var discoKey key.DiscoPublic
|
var discoKey key.DiscoPublic
|
||||||
@ -741,11 +741,11 @@ func (de *endpoint) updateFromNode(n *tailcfg.Node, heartbeatDisabled bool) {
|
|||||||
discoKey = epDisco.key
|
discoKey = epDisco.key
|
||||||
}
|
}
|
||||||
|
|
||||||
if discoKey != n.DiscoKey {
|
if discoKey != n.DiscoKey() {
|
||||||
de.c.logf("[v1] magicsock: disco: node %s changed from %s to %s", de.publicKey.ShortString(), discoKey, n.DiscoKey)
|
de.c.logf("[v1] magicsock: disco: node %s changed from %s to %s", de.publicKey.ShortString(), discoKey, n.DiscoKey())
|
||||||
de.disco.Store(&endpointDisco{
|
de.disco.Store(&endpointDisco{
|
||||||
key: n.DiscoKey,
|
key: n.DiscoKey(),
|
||||||
short: n.DiscoKey.ShortString(),
|
short: n.DiscoKey().ShortString(),
|
||||||
})
|
})
|
||||||
de.debugUpdates.Add(EndpointChange{
|
de.debugUpdates.Add(EndpointChange{
|
||||||
When: time.Now(),
|
When: time.Now(),
|
||||||
@ -753,7 +753,7 @@ func (de *endpoint) updateFromNode(n *tailcfg.Node, heartbeatDisabled bool) {
|
|||||||
})
|
})
|
||||||
de.resetLocked()
|
de.resetLocked()
|
||||||
}
|
}
|
||||||
if n.DERP == "" {
|
if n.DERP() == "" {
|
||||||
if de.derpAddr.IsValid() {
|
if de.derpAddr.IsValid() {
|
||||||
de.debugUpdates.Add(EndpointChange{
|
de.debugUpdates.Add(EndpointChange{
|
||||||
When: time.Now(),
|
When: time.Now(),
|
||||||
@ -763,7 +763,7 @@ func (de *endpoint) updateFromNode(n *tailcfg.Node, heartbeatDisabled bool) {
|
|||||||
}
|
}
|
||||||
de.derpAddr = netip.AddrPort{}
|
de.derpAddr = netip.AddrPort{}
|
||||||
} else {
|
} else {
|
||||||
newDerp, _ := netip.ParseAddrPort(n.DERP)
|
newDerp, _ := netip.ParseAddrPort(n.DERP())
|
||||||
if de.derpAddr != newDerp {
|
if de.derpAddr != newDerp {
|
||||||
de.debugUpdates.Add(EndpointChange{
|
de.debugUpdates.Add(EndpointChange{
|
||||||
When: time.Now(),
|
When: time.Now(),
|
||||||
@ -780,7 +780,8 @@ func (de *endpoint) updateFromNode(n *tailcfg.Node, heartbeatDisabled bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var newIpps []netip.AddrPort
|
var newIpps []netip.AddrPort
|
||||||
for i, epStr := range n.Endpoints {
|
for i := range n.Endpoints().LenIter() {
|
||||||
|
epStr := n.Endpoints().At(i)
|
||||||
if i > math.MaxInt16 {
|
if i > math.MaxInt16 {
|
||||||
// Seems unlikely.
|
// Seems unlikely.
|
||||||
continue
|
continue
|
||||||
|
@ -711,7 +711,7 @@ func (c *Conn) LastRecvActivityOfNodeKey(nk key.NodePublic) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ping handles a "tailscale ping" CLI query.
|
// Ping handles a "tailscale ping" CLI query.
|
||||||
func (c *Conn) Ping(peer *tailcfg.Node, res *ipnstate.PingResult, size int, cb func(*ipnstate.PingResult)) {
|
func (c *Conn) Ping(peer tailcfg.NodeView, res *ipnstate.PingResult, size int, cb func(*ipnstate.PingResult)) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
if c.privateKey.IsZero() {
|
if c.privateKey.IsZero() {
|
||||||
@ -719,17 +719,17 @@ func (c *Conn) Ping(peer *tailcfg.Node, res *ipnstate.PingResult, size int, cb f
|
|||||||
cb(res)
|
cb(res)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(peer.Addresses) > 0 {
|
if peer.Addresses().Len() > 0 {
|
||||||
res.NodeIP = peer.Addresses[0].Addr().String()
|
res.NodeIP = peer.Addresses().At(0).Addr().String()
|
||||||
}
|
}
|
||||||
res.NodeName = peer.Name // prefer DNS name
|
res.NodeName = peer.Name() // prefer DNS name
|
||||||
if res.NodeName == "" {
|
if res.NodeName == "" {
|
||||||
res.NodeName = peer.Hostinfo.Hostname() // else hostname
|
res.NodeName = peer.Hostinfo().Hostname() // else hostname
|
||||||
} else {
|
} else {
|
||||||
res.NodeName, _, _ = strings.Cut(res.NodeName, ".")
|
res.NodeName, _, _ = strings.Cut(res.NodeName, ".")
|
||||||
}
|
}
|
||||||
|
|
||||||
ep, ok := c.peerMap.endpointForNodeKey(peer.Key)
|
ep, ok := c.peerMap.endpointForNodeKey(peer.Key())
|
||||||
if !ok {
|
if !ok {
|
||||||
res.Err = "unknown peer"
|
res.Err = "unknown peer"
|
||||||
cb(res)
|
cb(res)
|
||||||
@ -753,13 +753,13 @@ func (c *Conn) populateCLIPingResponseLocked(res *ipnstate.PingResult, latency t
|
|||||||
// GetEndpointChanges returns the most recent changes for a particular
|
// GetEndpointChanges returns the most recent changes for a particular
|
||||||
// endpoint. The returned EndpointChange structs are for debug use only and
|
// endpoint. The returned EndpointChange structs are for debug use only and
|
||||||
// there are no guarantees about order, size, or content.
|
// there are no guarantees about order, size, or content.
|
||||||
func (c *Conn) GetEndpointChanges(peer *tailcfg.Node) ([]EndpointChange, error) {
|
func (c *Conn) GetEndpointChanges(peer tailcfg.NodeView) ([]EndpointChange, error) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
if c.privateKey.IsZero() {
|
if c.privateKey.IsZero() {
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
return nil, fmt.Errorf("tailscaled stopped")
|
return nil, fmt.Errorf("tailscaled stopped")
|
||||||
}
|
}
|
||||||
ep, ok := c.peerMap.endpointForNodeKey(peer.Key)
|
ep, ok := c.peerMap.endpointForNodeKey(peer.Key())
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -1729,7 +1729,7 @@ func (c *Conn) UpdatePeers(newPeers map[key.NodePublic]struct{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodesEqual(x, y []*tailcfg.Node) bool {
|
func nodesEqual(x, y []tailcfg.NodeView) bool {
|
||||||
if len(x) != len(y) {
|
if len(x) != len(y) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -1800,8 +1800,8 @@ func (c *Conn) SetNetworkMap(nm *netmap.NetworkMap) {
|
|||||||
// we'll fall through to the next pass, which allocates but can
|
// we'll fall through to the next pass, which allocates but can
|
||||||
// handle full set updates.
|
// handle full set updates.
|
||||||
for _, n := range nm.Peers {
|
for _, n := range nm.Peers {
|
||||||
if ep, ok := c.peerMap.endpointForNodeKey(n.Key); ok {
|
if ep, ok := c.peerMap.endpointForNodeKey(n.Key()); ok {
|
||||||
if n.DiscoKey.IsZero() && !n.IsWireGuardOnly {
|
if n.DiscoKey().IsZero() && !n.IsWireGuardOnly() {
|
||||||
// Discokey transitioned from non-zero to zero? This should not
|
// Discokey transitioned from non-zero to zero? This should not
|
||||||
// happen in the wild, however it could mean:
|
// happen in the wild, however it could mean:
|
||||||
// 1. A node was downgraded from post 0.100 to pre 0.100.
|
// 1. A node was downgraded from post 0.100 to pre 0.100.
|
||||||
@ -1820,7 +1820,7 @@ func (c *Conn) SetNetworkMap(nm *netmap.NetworkMap) {
|
|||||||
c.peerMap.upsertEndpoint(ep, oldDiscoKey) // maybe update discokey mappings in peerMap
|
c.peerMap.upsertEndpoint(ep, oldDiscoKey) // maybe update discokey mappings in peerMap
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if n.DiscoKey.IsZero() && !n.IsWireGuardOnly {
|
if n.DiscoKey().IsZero() && !n.IsWireGuardOnly() {
|
||||||
// Ancient pre-0.100 node, which does not have a disco key, and will only be reachable via DERP.
|
// Ancient pre-0.100 node, which does not have a disco key, and will only be reachable via DERP.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -1828,30 +1828,30 @@ func (c *Conn) SetNetworkMap(nm *netmap.NetworkMap) {
|
|||||||
ep := &endpoint{
|
ep := &endpoint{
|
||||||
c: c,
|
c: c,
|
||||||
debugUpdates: ringbuffer.New[EndpointChange](entriesPerBuffer),
|
debugUpdates: ringbuffer.New[EndpointChange](entriesPerBuffer),
|
||||||
publicKey: n.Key,
|
publicKey: n.Key(),
|
||||||
publicKeyHex: n.Key.UntypedHexString(),
|
publicKeyHex: n.Key().UntypedHexString(),
|
||||||
sentPing: map[stun.TxID]sentPing{},
|
sentPing: map[stun.TxID]sentPing{},
|
||||||
endpointState: map[netip.AddrPort]*endpointState{},
|
endpointState: map[netip.AddrPort]*endpointState{},
|
||||||
heartbeatDisabled: heartbeatDisabled,
|
heartbeatDisabled: heartbeatDisabled,
|
||||||
isWireguardOnly: n.IsWireGuardOnly,
|
isWireguardOnly: n.IsWireGuardOnly(),
|
||||||
}
|
}
|
||||||
if len(n.Addresses) > 0 {
|
if n.Addresses().Len() > 0 {
|
||||||
ep.nodeAddr = n.Addresses[0].Addr()
|
ep.nodeAddr = n.Addresses().At(0).Addr()
|
||||||
}
|
}
|
||||||
ep.initFakeUDPAddr()
|
ep.initFakeUDPAddr()
|
||||||
if n.DiscoKey.IsZero() {
|
if n.DiscoKey().IsZero() {
|
||||||
ep.disco.Store(nil)
|
ep.disco.Store(nil)
|
||||||
} else {
|
} else {
|
||||||
ep.disco.Store(&endpointDisco{
|
ep.disco.Store(&endpointDisco{
|
||||||
key: n.DiscoKey,
|
key: n.DiscoKey(),
|
||||||
short: n.DiscoKey.ShortString(),
|
short: n.DiscoKey().ShortString(),
|
||||||
})
|
})
|
||||||
|
|
||||||
if debugDisco() { // rather than making a new knob
|
if debugDisco() { // rather than making a new knob
|
||||||
c.logf("magicsock: created endpoint key=%s: disco=%s; %v", n.Key.ShortString(), n.DiscoKey.ShortString(), logger.ArgWriter(func(w *bufio.Writer) {
|
c.logf("magicsock: created endpoint key=%s: disco=%s; %v", n.Key().ShortString(), n.DiscoKey().ShortString(), logger.ArgWriter(func(w *bufio.Writer) {
|
||||||
const derpPrefix = "127.3.3.40:"
|
const derpPrefix = "127.3.3.40:"
|
||||||
if strings.HasPrefix(n.DERP, derpPrefix) {
|
if strings.HasPrefix(n.DERP(), derpPrefix) {
|
||||||
ipp, _ := netip.ParseAddrPort(n.DERP)
|
ipp, _ := netip.ParseAddrPort(n.DERP())
|
||||||
regionID := int(ipp.Port())
|
regionID := int(ipp.Port())
|
||||||
code := c.derpRegionCodeLocked(regionID)
|
code := c.derpRegionCodeLocked(regionID)
|
||||||
if code != "" {
|
if code != "" {
|
||||||
@ -1860,14 +1860,16 @@ func (c *Conn) SetNetworkMap(nm *netmap.NetworkMap) {
|
|||||||
fmt.Fprintf(w, "derp=%v%s ", regionID, code)
|
fmt.Fprintf(w, "derp=%v%s ", regionID, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, a := range n.AllowedIPs {
|
for i := range n.AllowedIPs().LenIter() {
|
||||||
|
a := n.AllowedIPs().At(i)
|
||||||
if a.IsSingleIP() {
|
if a.IsSingleIP() {
|
||||||
fmt.Fprintf(w, "aip=%v ", a.Addr())
|
fmt.Fprintf(w, "aip=%v ", a.Addr())
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(w, "aip=%v ", a)
|
fmt.Fprintf(w, "aip=%v ", a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, ep := range n.Endpoints {
|
for i := range n.Endpoints().LenIter() {
|
||||||
|
ep := n.Endpoints().At(i)
|
||||||
fmt.Fprintf(w, "ep=%v ", ep)
|
fmt.Fprintf(w, "ep=%v ", ep)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
@ -1885,7 +1887,7 @@ func (c *Conn) SetNetworkMap(nm *netmap.NetworkMap) {
|
|||||||
if c.peerMap.nodeCount() != len(nm.Peers) {
|
if c.peerMap.nodeCount() != len(nm.Peers) {
|
||||||
keep := make(map[key.NodePublic]bool, len(nm.Peers))
|
keep := make(map[key.NodePublic]bool, len(nm.Peers))
|
||||||
for _, n := range nm.Peers {
|
for _, n := range nm.Peers {
|
||||||
keep[n.Key] = true
|
keep[n.Key()] = true
|
||||||
}
|
}
|
||||||
c.peerMap.forEachEndpoint(func(ep *endpoint) {
|
c.peerMap.forEachEndpoint(func(ep *endpoint) {
|
||||||
if !keep[ep.publicKey] {
|
if !keep[ep.publicKey] {
|
||||||
|
@ -284,7 +284,7 @@ func meshStacks(logf logger.Logf, mutateNetmap func(idx int, nm *netmap.NetworkM
|
|||||||
Endpoints: epStrings(eps[i]),
|
Endpoints: epStrings(eps[i]),
|
||||||
DERP: "127.3.3.40:1",
|
DERP: "127.3.3.40:1",
|
||||||
}
|
}
|
||||||
nm.Peers = append(nm.Peers, peer)
|
nm.Peers = append(nm.Peers, peer.View())
|
||||||
}
|
}
|
||||||
|
|
||||||
if mutateNetmap != nil {
|
if mutateNetmap != nil {
|
||||||
@ -304,7 +304,7 @@ func meshStacks(logf logger.Logf, mutateNetmap func(idx int, nm *netmap.NetworkM
|
|||||||
m.conn.SetNetworkMap(nm)
|
m.conn.SetNetworkMap(nm)
|
||||||
peerSet := make(map[key.NodePublic]struct{}, len(nm.Peers))
|
peerSet := make(map[key.NodePublic]struct{}, len(nm.Peers))
|
||||||
for _, peer := range nm.Peers {
|
for _, peer := range nm.Peers {
|
||||||
peerSet[peer.Key] = struct{}{}
|
peerSet[peer.Key()] = struct{}{}
|
||||||
}
|
}
|
||||||
m.conn.UpdatePeers(peerSet)
|
m.conn.UpdatePeers(peerSet)
|
||||||
wg, err := nmcfg.WGCfg(nm, logf, netmap.AllowSingleHosts, "")
|
wg, err := nmcfg.WGCfg(nm, logf, netmap.AllowSingleHosts, "")
|
||||||
@ -657,7 +657,9 @@ func TestDiscokeyChange(t *testing.T) {
|
|||||||
}
|
}
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
nm.Peers[0].DiscoKey = m1DiscoKey
|
mut := nm.Peers[0].AsStruct()
|
||||||
|
mut.DiscoKey = m1DiscoKey
|
||||||
|
nm.Peers[0] = mut.View()
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanupMesh := meshStacks(t.Logf, setm1Key, m1, m2)
|
cleanupMesh := meshStacks(t.Logf, setm1Key, m1, m2)
|
||||||
@ -1248,13 +1250,13 @@ func addTestEndpoint(tb testing.TB, conn *Conn, sendConn net.PacketConn) (key.No
|
|||||||
discoKey := key.DiscoPublicFromRaw32(mem.B([]byte{31: 1}))
|
discoKey := key.DiscoPublicFromRaw32(mem.B([]byte{31: 1}))
|
||||||
nodeKey := key.NodePublicFromRaw32(mem.B([]byte{0: 'N', 1: 'K', 31: 0}))
|
nodeKey := key.NodePublicFromRaw32(mem.B([]byte{0: 'N', 1: 'K', 31: 0}))
|
||||||
conn.SetNetworkMap(&netmap.NetworkMap{
|
conn.SetNetworkMap(&netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
Key: nodeKey,
|
Key: nodeKey,
|
||||||
DiscoKey: discoKey,
|
DiscoKey: discoKey,
|
||||||
Endpoints: []string{sendConn.LocalAddr().String()},
|
Endpoints: []string{sendConn.LocalAddr().String()},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
})
|
})
|
||||||
conn.SetPrivateKey(key.NodePrivateFromRaw32(mem.B([]byte{0: 1, 31: 0})))
|
conn.SetPrivateKey(key.NodePrivateFromRaw32(mem.B([]byte{0: 1, 31: 0})))
|
||||||
_, err := conn.ParseEndpoint(nodeKey.UntypedHexString())
|
_, err := conn.ParseEndpoint(nodeKey.UntypedHexString())
|
||||||
@ -1427,6 +1429,14 @@ func BenchmarkReceiveFrom_Native(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func nodeViews(v []*tailcfg.Node) []tailcfg.NodeView {
|
||||||
|
nv := make([]tailcfg.NodeView, len(v))
|
||||||
|
for i, n := range v {
|
||||||
|
nv[i] = n.View()
|
||||||
|
}
|
||||||
|
return nv
|
||||||
|
}
|
||||||
|
|
||||||
// Test that a netmap update where node changes its node key but
|
// Test that a netmap update where node changes its node key but
|
||||||
// doesn't change its disco key doesn't result in a broken state.
|
// doesn't change its disco key doesn't result in a broken state.
|
||||||
//
|
//
|
||||||
@ -1444,13 +1454,13 @@ func TestSetNetworkMapChangingNodeKey(t *testing.T) {
|
|||||||
nodeKey2 := key.NodePublicFromRaw32(mem.B([]byte{0: 'N', 1: 'K', 2: '2', 31: 0}))
|
nodeKey2 := key.NodePublicFromRaw32(mem.B([]byte{0: 'N', 1: 'K', 2: '2', 31: 0}))
|
||||||
|
|
||||||
conn.SetNetworkMap(&netmap.NetworkMap{
|
conn.SetNetworkMap(&netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
Key: nodeKey1,
|
Key: nodeKey1,
|
||||||
DiscoKey: discoKey,
|
DiscoKey: discoKey,
|
||||||
Endpoints: []string{"192.168.1.2:345"},
|
Endpoints: []string{"192.168.1.2:345"},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
})
|
})
|
||||||
_, err := conn.ParseEndpoint(nodeKey1.UntypedHexString())
|
_, err := conn.ParseEndpoint(nodeKey1.UntypedHexString())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1459,13 +1469,13 @@ func TestSetNetworkMapChangingNodeKey(t *testing.T) {
|
|||||||
|
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
conn.SetNetworkMap(&netmap.NetworkMap{
|
conn.SetNetworkMap(&netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
Key: nodeKey2,
|
Key: nodeKey2,
|
||||||
DiscoKey: discoKey,
|
DiscoKey: discoKey,
|
||||||
Endpoints: []string{"192.168.1.2:345"},
|
Endpoints: []string{"192.168.1.2:345"},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1792,7 +1802,7 @@ func TestStressSetNetworkMap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
// Set the netmap.
|
// Set the netmap.
|
||||||
conn.SetNetworkMap(&netmap.NetworkMap{
|
conn.SetNetworkMap(&netmap.NetworkMap{
|
||||||
Peers: peers,
|
Peers: nodeViews(peers),
|
||||||
})
|
})
|
||||||
// Check invariants.
|
// Check invariants.
|
||||||
if err := conn.peerMap.validate(); err != nil {
|
if err := conn.peerMap.validate(); err != nil {
|
||||||
@ -2237,7 +2247,7 @@ func TestIsWireGuardOnlyPeer(t *testing.T) {
|
|||||||
PrivateKey: m.privateKey,
|
PrivateKey: m.privateKey,
|
||||||
NodeKey: m.privateKey.Public(),
|
NodeKey: m.privateKey.Public(),
|
||||||
Addresses: []netip.Prefix{tsaip},
|
Addresses: []netip.Prefix{tsaip},
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
Key: wgkey.Public(),
|
Key: wgkey.Public(),
|
||||||
Endpoints: []string{wgEp.String()},
|
Endpoints: []string{wgEp.String()},
|
||||||
@ -2245,7 +2255,7 @@ func TestIsWireGuardOnlyPeer(t *testing.T) {
|
|||||||
Addresses: []netip.Prefix{wgaip},
|
Addresses: []netip.Prefix{wgaip},
|
||||||
AllowedIPs: []netip.Prefix{wgaip},
|
AllowedIPs: []netip.Prefix{wgaip},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
}
|
}
|
||||||
m.conn.SetNetworkMap(nm)
|
m.conn.SetNetworkMap(nm)
|
||||||
|
|
||||||
@ -2295,7 +2305,7 @@ func TestIsWireGuardOnlyPeerWithMasquerade(t *testing.T) {
|
|||||||
PrivateKey: m.privateKey,
|
PrivateKey: m.privateKey,
|
||||||
NodeKey: m.privateKey.Public(),
|
NodeKey: m.privateKey.Public(),
|
||||||
Addresses: []netip.Prefix{tsaip},
|
Addresses: []netip.Prefix{tsaip},
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
Key: wgkey.Public(),
|
Key: wgkey.Public(),
|
||||||
Endpoints: []string{wgEp.String()},
|
Endpoints: []string{wgEp.String()},
|
||||||
@ -2304,7 +2314,7 @@ func TestIsWireGuardOnlyPeerWithMasquerade(t *testing.T) {
|
|||||||
AllowedIPs: []netip.Prefix{wgaip},
|
AllowedIPs: []netip.Prefix{wgaip},
|
||||||
SelfNodeV4MasqAddrForThisPeer: ptr.To(masqip.Addr()),
|
SelfNodeV4MasqAddrForThisPeer: ptr.To(masqip.Addr()),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
}
|
}
|
||||||
m.conn.SetNetworkMap(nm)
|
m.conn.SetNetworkMap(nm)
|
||||||
|
|
||||||
@ -2421,7 +2431,7 @@ func TestIsWireGuardOnlyPickEndpointByPing(t *testing.T) {
|
|||||||
PrivateKey: m.privateKey,
|
PrivateKey: m.privateKey,
|
||||||
NodeKey: m.privateKey.Public(),
|
NodeKey: m.privateKey.Public(),
|
||||||
Addresses: []netip.Prefix{tsaip},
|
Addresses: []netip.Prefix{tsaip},
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
Key: wgkey.Public(),
|
Key: wgkey.Public(),
|
||||||
Endpoints: []string{wgEp.String(), wgEp2.String(), wgEpV6.String()},
|
Endpoints: []string{wgEp.String(), wgEp2.String(), wgEpV6.String()},
|
||||||
@ -2429,7 +2439,7 @@ func TestIsWireGuardOnlyPickEndpointByPing(t *testing.T) {
|
|||||||
Addresses: []netip.Prefix{wgaip},
|
Addresses: []netip.Prefix{wgaip},
|
||||||
AllowedIPs: []netip.Prefix{wgaip},
|
AllowedIPs: []netip.Prefix{wgaip},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
applyNetworkMap(t, m, nm)
|
applyNetworkMap(t, m, nm)
|
||||||
|
@ -146,21 +146,22 @@ func (e *userspaceEngine) onOpenTimeout(flow flowtrack.Tuple) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
n := pip.Node
|
n := pip.Node
|
||||||
if !n.IsWireGuardOnly {
|
if !n.IsWireGuardOnly() {
|
||||||
if n.DiscoKey.IsZero() {
|
if n.DiscoKey().IsZero() {
|
||||||
e.logf("open-conn-track: timeout opening %v; peer node %v running pre-0.100", flow, n.Key.ShortString())
|
e.logf("open-conn-track: timeout opening %v; peer node %v running pre-0.100", flow, n.Key().ShortString())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if n.DERP == "" {
|
if n.DERP() == "" {
|
||||||
e.logf("open-conn-track: timeout opening %v; peer node %v not connected to any DERP relay", flow, n.Key.ShortString())
|
e.logf("open-conn-track: timeout opening %v; peer node %v not connected to any DERP relay", flow, n.Key().ShortString())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ps, found := e.getPeerStatusLite(n.Key)
|
ps, found := e.getPeerStatusLite(n.Key())
|
||||||
if !found {
|
if !found {
|
||||||
onlyZeroRoute := true // whether peerForIP returned n only because its /0 route matched
|
onlyZeroRoute := true // whether peerForIP returned n only because its /0 route matched
|
||||||
for _, r := range n.AllowedIPs {
|
for i := range n.AllowedIPs().LenIter() {
|
||||||
|
r := n.AllowedIPs().At(i)
|
||||||
if r.Bits() != 0 && r.Contains(flow.Dst.Addr()) {
|
if r.Bits() != 0 && r.Contains(flow.Dst.Addr()) {
|
||||||
onlyZeroRoute = false
|
onlyZeroRoute = false
|
||||||
break
|
break
|
||||||
@ -178,7 +179,7 @@ func (e *userspaceEngine) onOpenTimeout(flow flowtrack.Tuple) {
|
|||||||
// node.
|
// node.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
e.logf("open-conn-track: timeout opening %v; target node %v in netmap but unknown to WireGuard", flow, n.Key.ShortString())
|
e.logf("open-conn-track: timeout opening %v; target node %v in netmap but unknown to WireGuard", flow, n.Key().ShortString())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,24 +190,24 @@ func (e *userspaceEngine) onOpenTimeout(flow flowtrack.Tuple) {
|
|||||||
_ = ps.LastHandshake
|
_ = ps.LastHandshake
|
||||||
|
|
||||||
online := "?"
|
online := "?"
|
||||||
if n.IsWireGuardOnly {
|
if n.IsWireGuardOnly() {
|
||||||
online = "wg"
|
online = "wg"
|
||||||
} else {
|
} else {
|
||||||
if n.Online != nil {
|
if v := n.Online(); v != nil {
|
||||||
if *n.Online {
|
if *v {
|
||||||
online = "yes"
|
online = "yes"
|
||||||
} else {
|
} else {
|
||||||
online = "no"
|
online = "no"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if n.LastSeen != nil && online != "yes" {
|
if n.LastSeen() != nil && online != "yes" {
|
||||||
online += fmt.Sprintf(", lastseen=%v", durFmt(*n.LastSeen))
|
online += fmt.Sprintf(", lastseen=%v", durFmt(*n.LastSeen()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e.logf("open-conn-track: timeout opening %v to node %v; online=%v, lastRecv=%v",
|
e.logf("open-conn-track: timeout opening %v to node %v; online=%v, lastRecv=%v",
|
||||||
flow, n.Key.ShortString(),
|
flow, n.Key().ShortString(),
|
||||||
online,
|
online,
|
||||||
e.magicConn.LastRecvActivityOfNodeKey(n.Key))
|
e.magicConn.LastRecvActivityOfNodeKey(n.Key()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func durFmt(t time.Time) string {
|
func durFmt(t time.Time) string {
|
||||||
|
@ -1226,7 +1226,7 @@ func (e *userspaceEngine) Ping(ip netip.Addr, pingType tailcfg.PingType, size in
|
|||||||
}
|
}
|
||||||
peer := pip.Node
|
peer := pip.Node
|
||||||
|
|
||||||
e.logf("ping(%v): sending %v ping to %v %v ...", ip, pingType, peer.Key.ShortString(), peer.ComputedName)
|
e.logf("ping(%v): sending %v ping to %v %v ...", ip, pingType, peer.Key().ShortString(), peer.ComputedName())
|
||||||
switch pingType {
|
switch pingType {
|
||||||
case "disco":
|
case "disco":
|
||||||
e.magicConn.Ping(peer, res, size, cb)
|
e.magicConn.Ping(peer, res, size, cb)
|
||||||
@ -1254,7 +1254,7 @@ func (e *userspaceEngine) mySelfIPMatchingFamily(dst netip.Addr) (src netip.Addr
|
|||||||
return netip.Addr{}, errors.New("no self address in netmap matching address family")
|
return netip.Addr{}, errors.New("no self address in netmap matching address family")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *userspaceEngine) sendICMPEchoRequest(destIP netip.Addr, peer *tailcfg.Node, res *ipnstate.PingResult, cb func(*ipnstate.PingResult)) {
|
func (e *userspaceEngine) sendICMPEchoRequest(destIP netip.Addr, peer tailcfg.NodeView, res *ipnstate.PingResult, cb func(*ipnstate.PingResult)) {
|
||||||
srcIP, err := e.mySelfIPMatchingFamily(destIP)
|
srcIP, err := e.mySelfIPMatchingFamily(destIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.Err = err.Error()
|
res.Err = err.Error()
|
||||||
@ -1295,7 +1295,7 @@ func (e *userspaceEngine) sendICMPEchoRequest(destIP netip.Addr, peer *tailcfg.N
|
|||||||
d := time.Since(t0)
|
d := time.Since(t0)
|
||||||
res.LatencySeconds = d.Seconds()
|
res.LatencySeconds = d.Seconds()
|
||||||
res.NodeIP = destIP.String()
|
res.NodeIP = destIP.String()
|
||||||
res.NodeName = peer.ComputedName
|
res.NodeName = peer.ComputedName()
|
||||||
cb(res)
|
cb(res)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -1303,7 +1303,7 @@ func (e *userspaceEngine) sendICMPEchoRequest(destIP netip.Addr, peer *tailcfg.N
|
|||||||
e.tundev.InjectOutbound(icmpPing)
|
e.tundev.InjectOutbound(icmpPing)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *userspaceEngine) sendTSMPPing(ip netip.Addr, peer *tailcfg.Node, res *ipnstate.PingResult, cb func(*ipnstate.PingResult)) {
|
func (e *userspaceEngine) sendTSMPPing(ip netip.Addr, peer tailcfg.NodeView, res *ipnstate.PingResult, cb func(*ipnstate.PingResult)) {
|
||||||
srcIP, err := e.mySelfIPMatchingFamily(ip)
|
srcIP, err := e.mySelfIPMatchingFamily(ip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.Err = err.Error()
|
res.Err = err.Error()
|
||||||
@ -1337,7 +1337,7 @@ func (e *userspaceEngine) sendTSMPPing(ip netip.Addr, peer *tailcfg.Node, res *i
|
|||||||
d := time.Since(t0)
|
d := time.Since(t0)
|
||||||
res.LatencySeconds = d.Seconds()
|
res.LatencySeconds = d.Seconds()
|
||||||
res.NodeIP = ip.String()
|
res.NodeIP = ip.String()
|
||||||
res.NodeName = peer.ComputedName
|
res.NodeName = peer.ComputedName()
|
||||||
res.PeerAPIPort = pong.PeerAPIPort
|
res.PeerAPIPort = pong.PeerAPIPort
|
||||||
cb(res)
|
cb(res)
|
||||||
})
|
})
|
||||||
@ -1436,7 +1436,8 @@ func (e *userspaceEngine) PeerForIP(ip netip.Addr) (ret PeerForIP, ok bool) {
|
|||||||
// Check for exact matches before looking for subnet matches.
|
// Check for exact matches before looking for subnet matches.
|
||||||
// TODO(bradfitz): add maps for these. on NetworkMap?
|
// TODO(bradfitz): add maps for these. on NetworkMap?
|
||||||
for _, p := range nm.Peers {
|
for _, p := range nm.Peers {
|
||||||
for _, a := range p.Addresses {
|
for i := range p.Addresses().LenIter() {
|
||||||
|
a := p.Addresses().At(i)
|
||||||
if a.Addr() == ip && a.IsSingleIP() && tsaddr.IsTailscaleIP(ip) {
|
if a.Addr() == ip && a.IsSingleIP() && tsaddr.IsTailscaleIP(ip) {
|
||||||
return PeerForIP{Node: p, Route: a}, true
|
return PeerForIP{Node: p, Route: a}, true
|
||||||
}
|
}
|
||||||
@ -1444,7 +1445,7 @@ func (e *userspaceEngine) PeerForIP(ip netip.Addr) (ret PeerForIP, ok bool) {
|
|||||||
}
|
}
|
||||||
for _, a := range nm.Addresses {
|
for _, a := range nm.Addresses {
|
||||||
if a.Addr() == ip && a.IsSingleIP() && tsaddr.IsTailscaleIP(ip) {
|
if a.Addr() == ip && a.IsSingleIP() && tsaddr.IsTailscaleIP(ip) {
|
||||||
return PeerForIP{Node: nm.SelfNode, IsSelf: true, Route: a}, true
|
return PeerForIP{Node: nm.SelfNode.View(), IsSelf: true, Route: a}, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1469,7 +1470,7 @@ func (e *userspaceEngine) PeerForIP(ip netip.Addr) (ret PeerForIP, ok bool) {
|
|||||||
// call. But TODO(bradfitz): add a lookup map to netmap.NetworkMap.
|
// call. But TODO(bradfitz): add a lookup map to netmap.NetworkMap.
|
||||||
if !bestKey.IsZero() {
|
if !bestKey.IsZero() {
|
||||||
for _, p := range nm.Peers {
|
for _, p := range nm.Peers {
|
||||||
if p.Key == bestKey {
|
if p.Key() == bestKey {
|
||||||
return PeerForIP{Node: p, Route: best}, true
|
return PeerForIP{Node: p, Route: best}, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,14 @@ func TestNoteReceiveActivity(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func nodeViews(v []*tailcfg.Node) []tailcfg.NodeView {
|
||||||
|
nv := make([]tailcfg.NodeView, len(v))
|
||||||
|
for i, n := range v {
|
||||||
|
nv[i] = n.View()
|
||||||
|
}
|
||||||
|
return nv
|
||||||
|
}
|
||||||
|
|
||||||
func TestUserspaceEngineReconfig(t *testing.T) {
|
func TestUserspaceEngineReconfig(t *testing.T) {
|
||||||
e, err := NewFakeUserspaceEngine(t.Logf, 0)
|
e, err := NewFakeUserspaceEngine(t.Logf, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -99,11 +107,11 @@ func TestUserspaceEngineReconfig(t *testing.T) {
|
|||||||
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||||
} {
|
} {
|
||||||
nm := &netmap.NetworkMap{
|
nm := &netmap.NetworkMap{
|
||||||
Peers: []*tailcfg.Node{
|
Peers: nodeViews([]*tailcfg.Node{
|
||||||
{
|
{
|
||||||
Key: nkFromHex(nodeHex),
|
Key: nkFromHex(nodeHex),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
}
|
}
|
||||||
nk, err := key.ParseNodePublicUntyped(mem.S(nodeHex))
|
nk, err := key.ParseNodePublicUntyped(mem.S(nodeHex))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -19,30 +19,31 @@
|
|||||||
"tailscale.com/wgengine/wgcfg"
|
"tailscale.com/wgengine/wgcfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
func nodeDebugName(n *tailcfg.Node) string {
|
func nodeDebugName(n tailcfg.NodeView) string {
|
||||||
name := n.Name
|
name := n.Name()
|
||||||
if name == "" {
|
if name == "" {
|
||||||
name = n.Hostinfo.Hostname()
|
name = n.Hostinfo().Hostname()
|
||||||
}
|
}
|
||||||
if i := strings.Index(name, "."); i != -1 {
|
if i := strings.Index(name, "."); i != -1 {
|
||||||
name = name[:i]
|
name = name[:i]
|
||||||
}
|
}
|
||||||
if name == "" && len(n.Addresses) != 0 {
|
if name == "" && n.Addresses().Len() != 0 {
|
||||||
return n.Addresses[0].String()
|
return n.Addresses().At(0).String()
|
||||||
}
|
}
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
// cidrIsSubnet reports whether cidr is a non-default-route subnet
|
// cidrIsSubnet reports whether cidr is a non-default-route subnet
|
||||||
// exported by node that is not one of its own self addresses.
|
// exported by node that is not one of its own self addresses.
|
||||||
func cidrIsSubnet(node *tailcfg.Node, cidr netip.Prefix) bool {
|
func cidrIsSubnet(node tailcfg.NodeView, cidr netip.Prefix) bool {
|
||||||
if cidr.Bits() == 0 {
|
if cidr.Bits() == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !cidr.IsSingleIP() {
|
if !cidr.IsSingleIP() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
for _, selfCIDR := range node.Addresses {
|
for i := range node.Addresses().LenIter() {
|
||||||
|
selfCIDR := node.Addresses().At(i)
|
||||||
if cidr == selfCIDR {
|
if cidr == selfCIDR {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -85,22 +86,23 @@ func WGCfg(nm *netmap.NetworkMap, logf logger.Logf, flags netmap.WGConfigFlags,
|
|||||||
skippedSubnets := new(bytes.Buffer)
|
skippedSubnets := new(bytes.Buffer)
|
||||||
|
|
||||||
for _, peer := range nm.Peers {
|
for _, peer := range nm.Peers {
|
||||||
if peer.DiscoKey.IsZero() && peer.DERP == "" && !peer.IsWireGuardOnly {
|
if peer.DiscoKey().IsZero() && peer.DERP() == "" && !peer.IsWireGuardOnly() {
|
||||||
// Peer predates both DERP and active discovery, we cannot
|
// Peer predates both DERP and active discovery, we cannot
|
||||||
// communicate with it.
|
// communicate with it.
|
||||||
logf("[v1] wgcfg: skipped peer %s, doesn't offer DERP or disco", peer.Key.ShortString())
|
logf("[v1] wgcfg: skipped peer %s, doesn't offer DERP or disco", peer.Key().ShortString())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cfg.Peers = append(cfg.Peers, wgcfg.Peer{
|
cfg.Peers = append(cfg.Peers, wgcfg.Peer{
|
||||||
PublicKey: peer.Key,
|
PublicKey: peer.Key(),
|
||||||
DiscoKey: peer.DiscoKey,
|
DiscoKey: peer.DiscoKey(),
|
||||||
})
|
})
|
||||||
cpeer := &cfg.Peers[len(cfg.Peers)-1]
|
cpeer := &cfg.Peers[len(cfg.Peers)-1]
|
||||||
|
|
||||||
didExitNodeWarn := false
|
didExitNodeWarn := false
|
||||||
cpeer.V4MasqAddr = peer.SelfNodeV4MasqAddrForThisPeer
|
cpeer.V4MasqAddr = peer.SelfNodeV4MasqAddrForThisPeer()
|
||||||
for _, allowedIP := range peer.AllowedIPs {
|
for i := range peer.AllowedIPs().LenIter() {
|
||||||
if allowedIP.Bits() == 0 && peer.StableID != exitNode {
|
allowedIP := peer.AllowedIPs().At(i)
|
||||||
|
if allowedIP.Bits() == 0 && peer.StableID() != exitNode {
|
||||||
if didExitNodeWarn {
|
if didExitNodeWarn {
|
||||||
// Don't log about both the IPv4 /0 and IPv6 /0.
|
// Don't log about both the IPv4 /0 and IPv6 /0.
|
||||||
continue
|
continue
|
||||||
@ -109,20 +111,20 @@ func WGCfg(nm *netmap.NetworkMap, logf logger.Logf, flags netmap.WGConfigFlags,
|
|||||||
if skippedUnselected.Len() > 0 {
|
if skippedUnselected.Len() > 0 {
|
||||||
skippedUnselected.WriteString(", ")
|
skippedUnselected.WriteString(", ")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(skippedUnselected, "%q (%v)", nodeDebugName(peer), peer.Key.ShortString())
|
fmt.Fprintf(skippedUnselected, "%q (%v)", nodeDebugName(peer), peer.Key().ShortString())
|
||||||
continue
|
continue
|
||||||
} else if allowedIP.IsSingleIP() && tsaddr.IsTailscaleIP(allowedIP.Addr()) && (flags&netmap.AllowSingleHosts) == 0 {
|
} else if allowedIP.IsSingleIP() && tsaddr.IsTailscaleIP(allowedIP.Addr()) && (flags&netmap.AllowSingleHosts) == 0 {
|
||||||
if skippedIPs.Len() > 0 {
|
if skippedIPs.Len() > 0 {
|
||||||
skippedIPs.WriteString(", ")
|
skippedIPs.WriteString(", ")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(skippedIPs, "%v from %q (%v)", allowedIP.Addr(), nodeDebugName(peer), peer.Key.ShortString())
|
fmt.Fprintf(skippedIPs, "%v from %q (%v)", allowedIP.Addr(), nodeDebugName(peer), peer.Key().ShortString())
|
||||||
continue
|
continue
|
||||||
} else if cidrIsSubnet(peer, allowedIP) {
|
} else if cidrIsSubnet(peer, allowedIP) {
|
||||||
if (flags & netmap.AllowSubnetRoutes) == 0 {
|
if (flags & netmap.AllowSubnetRoutes) == 0 {
|
||||||
if skippedSubnets.Len() > 0 {
|
if skippedSubnets.Len() > 0 {
|
||||||
skippedSubnets.WriteString(", ")
|
skippedSubnets.WriteString(", ")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(skippedSubnets, "%v from %q (%v)", allowedIP, nodeDebugName(peer), peer.Key.ShortString())
|
fmt.Fprintf(skippedSubnets, "%v from %q (%v)", allowedIP, nodeDebugName(peer), peer.Key().ShortString())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,9 +52,9 @@ type someHandle struct{
|
|||||||
|
|
||||||
// PeerForIP is the type returned by Engine.PeerForIP.
|
// PeerForIP is the type returned by Engine.PeerForIP.
|
||||||
type PeerForIP struct {
|
type PeerForIP struct {
|
||||||
// Node is the matched node. It's always non-nil when
|
// Node is the matched node. It's always a valid value when
|
||||||
// Engine.PeerForIP returns ok==true.
|
// Engine.PeerForIP returns ok==true.
|
||||||
Node *tailcfg.Node
|
Node tailcfg.NodeView
|
||||||
|
|
||||||
// IsSelf is whether the Node is the local process.
|
// IsSelf is whether the Node is the local process.
|
||||||
IsSelf bool
|
IsSelf bool
|
||||||
|
Loading…
Reference in New Issue
Block a user