types/netmap: remove NetworkMap.{Addresses,MachineStatus}

And convert all callers over to the methods that check SelfNode.

Now we don't have multiple ways to express things in tests (setting
fields on SelfNode vs NetworkMap, sometimes inconsistently) and don't
have multiple ways to check those two fields (often only checking one
or the other).

Updates #9443

Change-Id: I2d7ba1cf6556142d219fae2be6f484f528756e3c
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/9451/head
Brad Fitzpatrick 1 year ago committed by Brad Fitzpatrick
parent d25217c9db
commit 0d991249e1

@ -37,6 +37,7 @@ import (
"tailscale.com/safesocket" "tailscale.com/safesocket"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/tsd" "tailscale.com/tsd"
"tailscale.com/types/views"
"tailscale.com/wgengine" "tailscale.com/wgengine"
"tailscale.com/wgengine/netstack" "tailscale.com/wgengine/netstack"
"tailscale.com/words" "tailscale.com/words"
@ -249,7 +250,7 @@ func (i *jsIPN) run(jsCallbacks js.Value) {
Self: jsNetMapSelfNode{ Self: jsNetMapSelfNode{
jsNetMapNode: jsNetMapNode{ jsNetMapNode: jsNetMapNode{
Name: nm.Name, Name: nm.Name,
Addresses: mapSlice(nm.Addresses, func(a netip.Prefix) string { return a.Addr().String() }), Addresses: mapSliceView(nm.GetAddresses(), func(a netip.Prefix) string { return a.Addr().String() }),
NodeKey: nm.NodeKey.String(), NodeKey: nm.NodeKey.String(),
MachineKey: nm.MachineKey.String(), MachineKey: nm.MachineKey.String(),
}, },
@ -578,6 +579,14 @@ func mapSlice[T any, M any](a []T, f func(T) M) []M {
return n return n
} }
func mapSliceView[T any, M any](a views.Slice[T], f func(T) M) []M {
n := make([]M, a.Len())
for i := range a.LenIter() {
n[i] = f(a.At(i))
}
return n
}
func filterSlice[T any](a []T, f func(T) bool) []T { func filterSlice[T any](a []T, f func(T) bool) []T {
n := make([]T, 0, len(a)) n := make([]T, 0, len(a))
for _, e := range a { for _, e := range a {

@ -752,12 +752,6 @@ func (ms *mapSession) netmap() *netmap.NetworkMap {
nm.SelfNode = node nm.SelfNode = node
nm.Expiry = node.KeyExpiry() nm.Expiry = node.KeyExpiry()
nm.Name = node.Name() nm.Name = node.Name()
nm.Addresses = filterSelfAddresses(node.Addresses().AsSlice())
if node.MachineAuthorized() {
nm.MachineStatus = tailcfg.MachineAuthorized
} else {
nm.MachineStatus = tailcfg.MachineUnauthorized
}
} }
ms.addUserProfile(nm, nm.User()) ms.addUserProfile(nm, nm.User())

@ -69,8 +69,10 @@ func TestDNSConfigForNetmap(t *testing.T) {
{ {
name: "self_name_and_peers", name: "self_name_and_peers",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Name: "myname.net", Name: "myname.net",
Addresses: ipps("100.101.101.101"), SelfNode: (&tailcfg.Node{
Addresses: ipps("100.101.101.101"),
}).View(),
}, },
peers: nodeViews([]*tailcfg.Node{ peers: nodeViews([]*tailcfg.Node{
{ {
@ -106,8 +108,10 @@ func TestDNSConfigForNetmap(t *testing.T) {
// even if they have IPv4. // even if they have IPv4.
name: "v6_only_self", name: "v6_only_self",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Name: "myname.net", Name: "myname.net",
Addresses: ipps("fe75::1"), SelfNode: (&tailcfg.Node{
Addresses: ipps("fe75::1"),
}).View(),
}, },
peers: nodeViews([]*tailcfg.Node{ peers: nodeViews([]*tailcfg.Node{
{ {
@ -141,8 +145,10 @@ func TestDNSConfigForNetmap(t *testing.T) {
{ {
name: "extra_records", name: "extra_records",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Name: "myname.net", Name: "myname.net",
Addresses: ipps("100.101.101.101"), SelfNode: (&tailcfg.Node{
Addresses: ipps("100.101.101.101"),
}).View(),
DNS: tailcfg.DNSConfig{ DNS: tailcfg.DNSConfig{
ExtraRecords: []tailcfg.DNSRecord{ ExtraRecords: []tailcfg.DNSRecord{
{Name: "foo.com", Value: "1.2.3.4"}, {Name: "foo.com", Value: "1.2.3.4"},

@ -2411,13 +2411,13 @@ func (b *LocalBackend) setAtomicValuesFromPrefsLocked(p ipn.PrefsView) {
b.sshAtomicBool.Store(p.Valid() && p.RunSSH() && envknob.CanSSHD()) b.sshAtomicBool.Store(p.Valid() && p.RunSSH() && envknob.CanSSHD())
if !p.Valid() { if !p.Valid() {
b.containsViaIPFuncAtomic.Store(tsaddr.NewContainsIPFunc(nil)) b.containsViaIPFuncAtomic.Store(tsaddr.FalseContainsIPFunc())
b.setTCPPortsIntercepted(nil) b.setTCPPortsIntercepted(nil)
b.lastServeConfJSON = mem.B(nil) b.lastServeConfJSON = mem.B(nil)
b.serveConfig = ipn.ServeConfigView{} b.serveConfig = ipn.ServeConfigView{}
} else { } else {
filtered := tsaddr.FilterPrefixesCopy(p.AdvertiseRoutes(), tsaddr.IsViaPrefix) filtered := tsaddr.FilterPrefixesCopy(p.AdvertiseRoutes(), tsaddr.IsViaPrefix)
b.containsViaIPFuncAtomic.Store(tsaddr.NewContainsIPFunc(filtered)) b.containsViaIPFuncAtomic.Store(tsaddr.NewContainsIPFunc(views.SliceOf(filtered)))
b.setTCPPortsInterceptedFromNetmapAndPrefsLocked(p) b.setTCPPortsInterceptedFromNetmapAndPrefsLocked(p)
} }
} }
@ -3211,8 +3211,8 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, peers map[tailcfg.NodeID]tailcfg.
} }
// selfV6Only is whether we only have IPv6 addresses ourselves. // selfV6Only is whether we only have IPv6 addresses ourselves.
selfV6Only := slices.ContainsFunc(nm.Addresses, tsaddr.PrefixIs6) && selfV6Only := views.SliceContainsFunc(nm.GetAddresses(), tsaddr.PrefixIs6) &&
!slices.ContainsFunc(nm.Addresses, tsaddr.PrefixIs4) !views.SliceContainsFunc(nm.GetAddresses(), tsaddr.PrefixIs4)
dcfg.OnlyIPv6 = selfV6Only dcfg.OnlyIPv6 = selfV6Only
// Populate MagicDNS records. We do this unconditionally so that // Populate MagicDNS records. We do this unconditionally so that
@ -3259,7 +3259,7 @@ func dnsConfigForNetmap(nm *netmap.NetworkMap, peers map[tailcfg.NodeID]tailcfg.
} }
dcfg.Hosts[fqdn] = ips dcfg.Hosts[fqdn] = ips
} }
set(nm.Name, views.SliceOf(nm.Addresses)) set(nm.Name, nm.GetAddresses())
for _, peer := range peers { for _, peer := range peers {
set(peer.Name(), peer.Addresses()) set(peer.Name(), peer.Addresses())
} }
@ -4595,7 +4595,9 @@ func peerAPIBase(nm *netmap.NetworkMap, peer tailcfg.NodeView) string {
} }
var have4, have6 bool var have4, have6 bool
for _, a := range nm.Addresses { addrs := nm.GetAddresses()
for i := range addrs.LenIter() {
a := addrs.At(i)
if !a.IsSingleIP() { if !a.IsSingleIP() {
continue continue
} }

@ -279,9 +279,11 @@ func TestPeerAPIBase(t *testing.T) {
{ {
name: "self_only_4_them_both", name: "self_only_4_them_both",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Addresses: []netip.Prefix{ SelfNode: (&tailcfg.Node{
netip.MustParsePrefix("100.64.1.1/32"), Addresses: []netip.Prefix{
}, netip.MustParsePrefix("100.64.1.1/32"),
},
}).View(),
}, },
peer: &tailcfg.Node{ peer: &tailcfg.Node{
Addresses: []netip.Prefix{ Addresses: []netip.Prefix{
@ -300,9 +302,11 @@ func TestPeerAPIBase(t *testing.T) {
{ {
name: "self_only_6_them_both", name: "self_only_6_them_both",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Addresses: []netip.Prefix{ SelfNode: (&tailcfg.Node{
netip.MustParsePrefix("fe70::1/128"), Addresses: []netip.Prefix{
}, netip.MustParsePrefix("fe70::1/128"),
},
}).View(),
}, },
peer: &tailcfg.Node{ peer: &tailcfg.Node{
Addresses: []netip.Prefix{ Addresses: []netip.Prefix{
@ -321,10 +325,12 @@ func TestPeerAPIBase(t *testing.T) {
{ {
name: "self_both_them_only_4", name: "self_both_them_only_4",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Addresses: []netip.Prefix{ SelfNode: (&tailcfg.Node{
netip.MustParsePrefix("100.64.1.1/32"), Addresses: []netip.Prefix{
netip.MustParsePrefix("fe70::1/128"), netip.MustParsePrefix("100.64.1.1/32"),
}, netip.MustParsePrefix("fe70::1/128"),
},
}).View(),
}, },
peer: &tailcfg.Node{ peer: &tailcfg.Node{
Addresses: []netip.Prefix{ Addresses: []netip.Prefix{
@ -342,10 +348,12 @@ func TestPeerAPIBase(t *testing.T) {
{ {
name: "self_both_them_only_6", name: "self_both_them_only_6",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Addresses: []netip.Prefix{ SelfNode: (&tailcfg.Node{
netip.MustParsePrefix("100.64.1.1/32"), Addresses: []netip.Prefix{
netip.MustParsePrefix("fe70::1/128"), netip.MustParsePrefix("100.64.1.1/32"),
}, netip.MustParsePrefix("fe70::1/128"),
},
}).View(),
}, },
peer: &tailcfg.Node{ peer: &tailcfg.Node{
Addresses: []netip.Prefix{ Addresses: []netip.Prefix{
@ -363,10 +371,12 @@ func TestPeerAPIBase(t *testing.T) {
{ {
name: "self_both_them_no_peerapi_service", name: "self_both_them_no_peerapi_service",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Addresses: []netip.Prefix{ SelfNode: (&tailcfg.Node{
netip.MustParsePrefix("100.64.1.1/32"), Addresses: []netip.Prefix{
netip.MustParsePrefix("fe70::1/128"), netip.MustParsePrefix("100.64.1.1/32"),
}, netip.MustParsePrefix("fe70::1/128"),
},
}).View(),
}, },
peer: &tailcfg.Node{ peer: &tailcfg.Node{
Addresses: []netip.Prefix{ Addresses: []netip.Prefix{
@ -689,10 +699,9 @@ func TestStatusWithoutPeers(t *testing.T) {
b.Start(ipn.Options{}) b.Start(ipn.Options{})
b.Login(nil) b.Login(nil)
cc.send(nil, "", false, &netmap.NetworkMap{ cc.send(nil, "", false, &netmap.NetworkMap{
MachineStatus: tailcfg.MachineAuthorized,
Addresses: ipps("100.101.101.101"),
SelfNode: (&tailcfg.Node{ SelfNode: (&tailcfg.Node{
Addresses: ipps("100.101.101.101"), MachineAuthorized: true,
Addresses: ipps("100.101.101.101"),
}).View(), }).View(),
}) })
got := b.StatusWithoutPeers() got := b.StatusWithoutPeers()

@ -501,7 +501,7 @@ func TestStateMachine(t *testing.T) {
// (ie. I suspect it would be better to change false->true in send() // (ie. I suspect it would be better to change false->true in send()
// below, and do the same in the real controlclient.) // below, and do the same in the real controlclient.)
cc.send(nil, "", false, &netmap.NetworkMap{ cc.send(nil, "", false, &netmap.NetworkMap{
MachineStatus: tailcfg.MachineAuthorized, SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(),
}) })
{ {
nn := notifies.drain(1) nn := notifies.drain(1)
@ -665,7 +665,7 @@ func TestStateMachine(t *testing.T) {
cc.persist.UserProfile.LoginName = "user2" cc.persist.UserProfile.LoginName = "user2"
cc.persist.NodeID = "node2" cc.persist.NodeID = "node2"
cc.send(nil, "", true, &netmap.NetworkMap{ cc.send(nil, "", true, &netmap.NetworkMap{
MachineStatus: tailcfg.MachineAuthorized, SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(),
}) })
{ {
nn := notifies.drain(3) nn := notifies.drain(3)
@ -732,7 +732,7 @@ func TestStateMachine(t *testing.T) {
t.Logf("\n\nStart4 -> netmap") t.Logf("\n\nStart4 -> netmap")
notifies.expect(0) notifies.expect(0)
cc.send(nil, "", true, &netmap.NetworkMap{ cc.send(nil, "", true, &netmap.NetworkMap{
MachineStatus: tailcfg.MachineAuthorized, SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(),
}) })
{ {
notifies.drain(0) notifies.drain(0)
@ -801,7 +801,7 @@ func TestStateMachine(t *testing.T) {
cc.persist.UserProfile.LoginName = "user3" cc.persist.UserProfile.LoginName = "user3"
cc.persist.NodeID = "node3" cc.persist.NodeID = "node3"
cc.send(nil, "", true, &netmap.NetworkMap{ cc.send(nil, "", true, &netmap.NetworkMap{
MachineStatus: tailcfg.MachineAuthorized, SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(),
}) })
{ {
nn := notifies.drain(3) nn := notifies.drain(3)
@ -845,7 +845,7 @@ func TestStateMachine(t *testing.T) {
t.Logf("\n\nLoginFinished5") t.Logf("\n\nLoginFinished5")
notifies.expect(2) notifies.expect(2)
cc.send(nil, "", true, &netmap.NetworkMap{ cc.send(nil, "", true, &netmap.NetworkMap{
MachineStatus: tailcfg.MachineAuthorized, SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(),
}) })
{ {
nn := notifies.drain(2) nn := notifies.drain(2)
@ -862,8 +862,8 @@ func TestStateMachine(t *testing.T) {
t.Logf("\n\nExpireKey") t.Logf("\n\nExpireKey")
notifies.expect(1) notifies.expect(1)
cc.send(nil, "", false, &netmap.NetworkMap{ cc.send(nil, "", false, &netmap.NetworkMap{
Expiry: time.Now().Add(-time.Minute), Expiry: time.Now().Add(-time.Minute),
MachineStatus: tailcfg.MachineAuthorized, SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(),
}) })
{ {
nn := notifies.drain(1) nn := notifies.drain(1)
@ -877,8 +877,8 @@ func TestStateMachine(t *testing.T) {
t.Logf("\n\nExtendKey") t.Logf("\n\nExtendKey")
notifies.expect(1) notifies.expect(1)
cc.send(nil, "", false, &netmap.NetworkMap{ cc.send(nil, "", false, &netmap.NetworkMap{
Expiry: time.Now().Add(time.Minute), Expiry: time.Now().Add(time.Minute),
MachineStatus: tailcfg.MachineAuthorized, SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(),
}) })
{ {
nn := notifies.drain(1) nn := notifies.drain(1)
@ -1023,7 +1023,7 @@ func TestWGEngineStatusRace(t *testing.T) {
// Assert that we are logged in and authorized. // Assert that we are logged in and authorized.
cc.send(nil, "", true, &netmap.NetworkMap{ cc.send(nil, "", true, &netmap.NetworkMap{
MachineStatus: tailcfg.MachineAuthorized, SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(),
}) })
wantState(ipn.Starting) wantState(ipn.Starting)

@ -161,6 +161,11 @@ type oncePrefix struct {
v netip.Prefix v netip.Prefix
} }
// FalseContainsIPFunc is shorthand for NewContainsIPFunc(views.Slice[netip.Prefix]{}).
func FalseContainsIPFunc() func(ip netip.Addr) bool {
return func(ip netip.Addr) bool { return false }
}
// NewContainsIPFunc returns a func that reports whether ip is in addrs. // NewContainsIPFunc returns a func that reports whether ip is in addrs.
// //
// It's optimized for the cases of addrs being empty and addrs // It's optimized for the cases of addrs being empty and addrs
@ -168,20 +173,17 @@ type oncePrefix struct {
// one IPv6 address). // one IPv6 address).
// //
// Otherwise the implementation is somewhat slow. // Otherwise the implementation is somewhat slow.
func NewContainsIPFunc(addrs []netip.Prefix) func(ip netip.Addr) bool { func NewContainsIPFunc(addrs views.Slice[netip.Prefix]) func(ip netip.Addr) bool {
// Specialize the three common cases: no address, just IPv4 // Specialize the three common cases: no address, just IPv4
// (or just IPv6), and both IPv4 and IPv6. // (or just IPv6), and both IPv4 and IPv6.
if len(addrs) == 0 { if addrs.Len() == 0 {
return func(netip.Addr) bool { return false } return func(netip.Addr) bool { return false }
} }
// If any addr is more than a single IP, then just do the slow // If any addr is more than a single IP, then just do the slow
// linear thing until // linear thing until
// https://github.com/inetaf/netaddr/issues/139 is done. // https://github.com/inetaf/netaddr/issues/139 is done.
for _, a := range addrs { if views.SliceContainsFunc(addrs, func(p netip.Prefix) bool { return !p.IsSingleIP() }) {
if a.IsSingleIP() { acopy := addrs.AsSlice()
continue
}
acopy := append([]netip.Prefix(nil), addrs...)
return func(ip netip.Addr) bool { return func(ip netip.Addr) bool {
for _, a := range acopy { for _, a := range acopy {
if a.Contains(ip) { if a.Contains(ip) {
@ -192,18 +194,18 @@ func NewContainsIPFunc(addrs []netip.Prefix) func(ip netip.Addr) bool {
} }
} }
// Fast paths for 1 and 2 IPs: // Fast paths for 1 and 2 IPs:
if len(addrs) == 1 { if addrs.Len() == 1 {
a := addrs[0] a := addrs.At(0)
return func(ip netip.Addr) bool { return ip == a.Addr() } return func(ip netip.Addr) bool { return ip == a.Addr() }
} }
if len(addrs) == 2 { if addrs.Len() == 2 {
a, b := addrs[0], addrs[1] a, b := addrs.At(0), addrs.At(1)
return func(ip netip.Addr) bool { return ip == a.Addr() || ip == b.Addr() } return func(ip netip.Addr) bool { return ip == a.Addr() || ip == b.Addr() }
} }
// General case: // General case:
m := map[netip.Addr]bool{} m := map[netip.Addr]bool{}
for _, a := range addrs { for i := range addrs.LenIter() {
m[a.Addr()] = true m[addrs.At(i).Addr()] = true
} }
return func(ip netip.Addr) bool { return m[ip] } return func(ip netip.Addr) bool { return m[ip] }
} }

@ -8,6 +8,7 @@ import (
"testing" "testing"
"tailscale.com/net/netaddr" "tailscale.com/net/netaddr"
"tailscale.com/types/views"
) )
func TestInCrostiniRange(t *testing.T) { func TestInCrostiniRange(t *testing.T) {
@ -66,29 +67,29 @@ func TestCGNATRange(t *testing.T) {
} }
func TestNewContainsIPFunc(t *testing.T) { func TestNewContainsIPFunc(t *testing.T) {
f := NewContainsIPFunc([]netip.Prefix{netip.MustParsePrefix("10.0.0.0/8")}) f := NewContainsIPFunc(views.SliceOf([]netip.Prefix{netip.MustParsePrefix("10.0.0.0/8")}))
if f(netip.MustParseAddr("8.8.8.8")) { if f(netip.MustParseAddr("8.8.8.8")) {
t.Fatal("bad") t.Fatal("bad")
} }
if !f(netip.MustParseAddr("10.1.2.3")) { if !f(netip.MustParseAddr("10.1.2.3")) {
t.Fatal("bad") t.Fatal("bad")
} }
f = NewContainsIPFunc([]netip.Prefix{netip.MustParsePrefix("10.1.2.3/32")}) f = NewContainsIPFunc(views.SliceOf([]netip.Prefix{netip.MustParsePrefix("10.1.2.3/32")}))
if !f(netip.MustParseAddr("10.1.2.3")) { if !f(netip.MustParseAddr("10.1.2.3")) {
t.Fatal("bad") t.Fatal("bad")
} }
f = NewContainsIPFunc([]netip.Prefix{ f = NewContainsIPFunc(views.SliceOf([]netip.Prefix{
netip.MustParsePrefix("10.1.2.3/32"), netip.MustParsePrefix("10.1.2.3/32"),
netip.MustParsePrefix("::2/128"), netip.MustParsePrefix("::2/128"),
}) }))
if !f(netip.MustParseAddr("::2")) { if !f(netip.MustParseAddr("::2")) {
t.Fatal("bad") t.Fatal("bad")
} }
f = NewContainsIPFunc([]netip.Prefix{ f = NewContainsIPFunc(views.SliceOf([]netip.Prefix{
netip.MustParsePrefix("10.1.2.3/32"), netip.MustParsePrefix("10.1.2.3/32"),
netip.MustParsePrefix("10.1.2.4/32"), netip.MustParsePrefix("10.1.2.4/32"),
netip.MustParsePrefix("::2/128"), netip.MustParsePrefix("::2/128"),
}) }))
if !f(netip.MustParseAddr("10.1.2.4")) { if !f(netip.MustParseAddr("10.1.2.4")) {
t.Fatal("bad") t.Fatal("bad")
} }

@ -32,10 +32,12 @@ func TestDNSMapFromNetworkMap(t *testing.T) {
name: "self", name: "self",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Name: "foo.tailnet", Name: "foo.tailnet",
Addresses: []netip.Prefix{ SelfNode: (&tailcfg.Node{
pfx("100.102.103.104/32"), Addresses: []netip.Prefix{
pfx("100::123/128"), pfx("100.102.103.104/32"),
}, pfx("100::123/128"),
},
}).View(),
}, },
want: dnsMap{ want: dnsMap{
"foo": ip("100.102.103.104"), "foo": ip("100.102.103.104"),
@ -46,10 +48,12 @@ func TestDNSMapFromNetworkMap(t *testing.T) {
name: "self_and_peers", name: "self_and_peers",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Name: "foo.tailnet", Name: "foo.tailnet",
Addresses: []netip.Prefix{ SelfNode: (&tailcfg.Node{
pfx("100.102.103.104/32"), Addresses: []netip.Prefix{
pfx("100::123/128"), pfx("100.102.103.104/32"),
}, pfx("100::123/128"),
},
}).View(),
Peers: []tailcfg.NodeView{ Peers: []tailcfg.NodeView{
(&tailcfg.Node{ (&tailcfg.Node{
Name: "a.tailnet", Name: "a.tailnet",
@ -79,9 +83,11 @@ func TestDNSMapFromNetworkMap(t *testing.T) {
name: "self_has_v6_only", name: "self_has_v6_only",
nm: &netmap.NetworkMap{ nm: &netmap.NetworkMap{
Name: "foo.tailnet", Name: "foo.tailnet",
Addresses: []netip.Prefix{ SelfNode: (&tailcfg.Node{
pfx("100::123/128"), Addresses: []netip.Prefix{
}, pfx("100::123/128"),
},
}).View(),
Peers: nodeViews([]*tailcfg.Node{ Peers: nodeViews([]*tailcfg.Node{
{ {
Name: "a.tailnet", Name: "a.tailnet",

@ -33,20 +33,6 @@ type NetworkMap struct {
// It is the MapResponse.Node.Name value and ends with a period. // It is the MapResponse.Node.Name value and ends with a period.
Name string Name string
// Addresses is SelfNode.Addresses. (IP addresses of this Node directly)
//
// Deprecated: use GetAddresses instead. As of 2023-09-17, this field
// is being phased out.
Addresses []netip.Prefix
// MachineStatus is either tailcfg.MachineAuthorized or tailcfg.MachineUnauthorized,
// depending on SelfNode.MachineAuthorized.
//
// Deprecated: use GetMachineStatus instead. This field exists still
// exists (as of 2023-09-13) for some tests in other repos that haven't
// yet been migrated. TODO(bradfitz): remove this field.
MachineStatus tailcfg.MachineStatus
MachineKey key.MachinePublic MachineKey key.MachinePublic
Peers []tailcfg.NodeView // sorted by Node.ID Peers []tailcfg.NodeView // sorted by Node.ID
@ -104,12 +90,6 @@ func (nm *NetworkMap) User() tailcfg.UserID {
// if SelfNode is invalid. // if SelfNode is invalid.
func (nm *NetworkMap) GetAddresses() views.Slice[netip.Prefix] { func (nm *NetworkMap) GetAddresses() views.Slice[netip.Prefix] {
var zero views.Slice[netip.Prefix] var zero views.Slice[netip.Prefix]
if nm.Addresses != nil {
// For now (2023-09-17), let the deprecated Addressees field take
// precedence. This is a migration mechanism while we update tests &
// code cross-repo.
return views.SliceOf(nm.Addresses)
}
if !nm.SelfNode.Valid() { if !nm.SelfNode.Valid() {
return zero return zero
} }
@ -128,12 +108,6 @@ func (nm *NetworkMap) AnyPeersAdvertiseRoutes() bool {
// GetMachineStatus returns the MachineStatus of the local node. // GetMachineStatus returns the MachineStatus of the local node.
func (nm *NetworkMap) GetMachineStatus() tailcfg.MachineStatus { func (nm *NetworkMap) GetMachineStatus() tailcfg.MachineStatus {
if nm.MachineStatus != tailcfg.MachineUnknown {
// For now (2023-09-13), let the deprecated MachineStatus field take
// precedence. This is a migration mechanism while we update tests &
// code cross-repo.
return nm.MachineStatus
}
if !nm.SelfNode.Valid() { if !nm.SelfNode.Valid() {
return tailcfg.MachineUnknown return tailcfg.MachineUnknown
} }
@ -258,25 +232,17 @@ func (nm *NetworkMap) printConciseHeader(buf *strings.Builder) {
} }
} }
fmt.Fprintf(buf, " u=%s", login) fmt.Fprintf(buf, " u=%s", login)
fmt.Fprintf(buf, " %v", nm.Addresses) fmt.Fprintf(buf, " %v", nm.GetAddresses().AsSlice())
buf.WriteByte('\n') buf.WriteByte('\n')
} }
// equalConciseHeader reports whether a and b are equal for the fields // equalConciseHeader reports whether a and b are equal for the fields
// used by printConciseHeader. // used by printConciseHeader.
func (a *NetworkMap) equalConciseHeader(b *NetworkMap) bool { func (a *NetworkMap) equalConciseHeader(b *NetworkMap) bool {
if a.NodeKey != b.NodeKey || return a.NodeKey == b.NodeKey &&
a.GetMachineStatus() != b.GetMachineStatus() || a.GetMachineStatus() == b.GetMachineStatus() &&
a.User() != b.User() || a.User() == b.User() &&
len(a.Addresses) != len(b.Addresses) { views.SliceEqual(a.GetAddresses(), b.GetAddresses())
return false
}
for i, a := range a.Addresses {
if b.Addresses[i] != a {
return false
}
}
return true
} }
// printPeerConcise appends to buf a line representing the peer p. // printPeerConcise appends to buf a line representing the peer p.

@ -274,7 +274,9 @@ func meshStacks(logf logger.Logf, mutateNetmap func(idx int, nm *netmap.NetworkM
nm := &netmap.NetworkMap{ nm := &netmap.NetworkMap{
PrivateKey: me.privateKey, PrivateKey: me.privateKey,
NodeKey: me.privateKey.Public(), NodeKey: me.privateKey.Public(),
Addresses: []netip.Prefix{netip.PrefixFrom(netaddr.IPv4(1, 0, 0, byte(myIdx+1)), 32)}, SelfNode: (&tailcfg.Node{
Addresses: []netip.Prefix{netip.PrefixFrom(netaddr.IPv4(1, 0, 0, byte(myIdx+1)), 32)},
}).View(),
} }
for i, peer := range ms { for i, peer := range ms {
if i == myIdx { if i == myIdx {
@ -2267,7 +2269,9 @@ func TestIsWireGuardOnlyPeer(t *testing.T) {
Name: "ts", Name: "ts",
PrivateKey: m.privateKey, PrivateKey: m.privateKey,
NodeKey: m.privateKey.Public(), NodeKey: m.privateKey.Public(),
Addresses: []netip.Prefix{tsaip}, SelfNode: (&tailcfg.Node{
Addresses: []netip.Prefix{tsaip},
}).View(),
Peers: nodeViews([]*tailcfg.Node{ Peers: nodeViews([]*tailcfg.Node{
{ {
ID: 1, ID: 1,
@ -2326,7 +2330,9 @@ func TestIsWireGuardOnlyPeerWithMasquerade(t *testing.T) {
Name: "ts", Name: "ts",
PrivateKey: m.privateKey, PrivateKey: m.privateKey,
NodeKey: m.privateKey.Public(), NodeKey: m.privateKey.Public(),
Addresses: []netip.Prefix{tsaip}, SelfNode: (&tailcfg.Node{
Addresses: []netip.Prefix{tsaip},
}).View(),
Peers: nodeViews([]*tailcfg.Node{ Peers: nodeViews([]*tailcfg.Node{
{ {
ID: 1, ID: 1,
@ -2453,7 +2459,9 @@ func TestIsWireGuardOnlyPickEndpointByPing(t *testing.T) {
Name: "ts", Name: "ts",
PrivateKey: m.privateKey, PrivateKey: m.privateKey,
NodeKey: m.privateKey.Public(), NodeKey: m.privateKey.Public(),
Addresses: []netip.Prefix{tsaip}, SelfNode: (&tailcfg.Node{
Addresses: []netip.Prefix{tsaip},
}).View(),
Peers: nodeViews([]*tailcfg.Node{ Peers: nodeViews([]*tailcfg.Node{
{ {
Key: wgkey.Public(), Key: wgkey.Public(),

@ -221,7 +221,7 @@ func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magi
dns: dns, dns: dns,
} }
ns.ctx, ns.ctxCancel = context.WithCancel(context.Background()) ns.ctx, ns.ctxCancel = context.WithCancel(context.Background())
ns.atomicIsLocalIPFunc.Store(tsaddr.NewContainsIPFunc(nil)) ns.atomicIsLocalIPFunc.Store(tsaddr.FalseContainsIPFunc())
ns.tundev.PostFilterPacketInboundFromWireGaurd = ns.injectInbound ns.tundev.PostFilterPacketInboundFromWireGaurd = ns.injectInbound
ns.tundev.PreFilterPacketOutboundToWireGuardNetstackIntercept = ns.handleLocalPackets ns.tundev.PreFilterPacketOutboundToWireGuardNetstackIntercept = ns.handleLocalPackets
return ns, nil return ns, nil
@ -324,10 +324,10 @@ var v4broadcast = netaddr.IPv4(255, 255, 255, 255)
func (ns *Impl) UpdateNetstackIPs(nm *netmap.NetworkMap) { func (ns *Impl) UpdateNetstackIPs(nm *netmap.NetworkMap) {
var selfNode tailcfg.NodeView var selfNode tailcfg.NodeView
if nm != nil { if nm != nil {
ns.atomicIsLocalIPFunc.Store(tsaddr.NewContainsIPFunc(nm.Addresses)) ns.atomicIsLocalIPFunc.Store(tsaddr.NewContainsIPFunc(nm.GetAddresses()))
selfNode = nm.SelfNode selfNode = nm.SelfNode
} else { } else {
ns.atomicIsLocalIPFunc.Store(tsaddr.NewContainsIPFunc(nil)) ns.atomicIsLocalIPFunc.Store(tsaddr.FalseContainsIPFunc())
} }
oldIPs := make(map[tcpip.AddressWithPrefix]bool) oldIPs := make(map[tcpip.AddressWithPrefix]bool)

@ -286,8 +286,8 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
return nil, err return nil, err
} }
} }
e.isLocalAddr.Store(tsaddr.NewContainsIPFunc(nil)) e.isLocalAddr.Store(tsaddr.FalseContainsIPFunc())
e.isDNSIPOverTailscale.Store(tsaddr.NewContainsIPFunc(nil)) e.isDNSIPOverTailscale.Store(tsaddr.FalseContainsIPFunc())
if conf.NetMon != nil { if conf.NetMon != nil {
e.netMon = conf.NetMon e.netMon = conf.NetMon
@ -782,7 +782,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
panic("dnsCfg must not be nil") panic("dnsCfg must not be nil")
} }
e.isLocalAddr.Store(tsaddr.NewContainsIPFunc(routerCfg.LocalAddrs)) e.isLocalAddr.Store(tsaddr.NewContainsIPFunc(views.SliceOf(routerCfg.LocalAddrs)))
e.wgLock.Lock() e.wgLock.Lock()
defer e.wgLock.Unlock() defer e.wgLock.Unlock()
@ -836,7 +836,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
// instead have ipnlocal populate a map of DNS IP => linkName and // instead have ipnlocal populate a map of DNS IP => linkName and
// put that in the *dns.Config instead, and plumb it down to the // put that in the *dns.Config instead, and plumb it down to the
// dns.Manager. Maybe also with isLocalAddr above. // dns.Manager. Maybe also with isLocalAddr above.
e.isDNSIPOverTailscale.Store(tsaddr.NewContainsIPFunc(dnsIPsOverTailscale(dnsCfg, routerCfg))) e.isDNSIPOverTailscale.Store(tsaddr.NewContainsIPFunc(views.SliceOf(dnsIPsOverTailscale(dnsCfg, routerCfg))))
// See if any peers have changed disco keys, which means they've restarted. // See if any peers have changed disco keys, which means they've restarted.
// If so, we need to update the wireguard-go/device.Device in two phases: // If so, we need to update the wireguard-go/device.Device in two phases:
@ -1205,20 +1205,22 @@ func (e *userspaceEngine) Ping(ip netip.Addr, pingType tailcfg.PingType, size in
} }
func (e *userspaceEngine) mySelfIPMatchingFamily(dst netip.Addr) (src netip.Addr, err error) { func (e *userspaceEngine) mySelfIPMatchingFamily(dst netip.Addr) (src netip.Addr, err error) {
var zero netip.Addr
e.mu.Lock() e.mu.Lock()
defer e.mu.Unlock() defer e.mu.Unlock()
if e.netMap == nil { if e.netMap == nil {
return netip.Addr{}, errors.New("no netmap") return zero, errors.New("no netmap")
} }
for _, a := range e.netMap.Addresses { addrs := e.netMap.GetAddresses()
if a.IsSingleIP() && a.Addr().BitLen() == dst.BitLen() { if addrs.Len() == 0 {
return zero, errors.New("no self address in netmap")
}
for i := range addrs.LenIter() {
if a := addrs.At(i); a.IsSingleIP() && a.Addr().BitLen() == dst.BitLen() {
return a.Addr(), nil return a.Addr(), nil
} }
} }
if len(e.netMap.Addresses) == 0 { return zero, errors.New("no self address in netmap matching address family")
return netip.Addr{}, errors.New("no self address in netmap")
}
return netip.Addr{}, errors.New("no self address in netmap matching address family")
} }
func (e *userspaceEngine) sendICMPEchoRequest(destIP netip.Addr, peer tailcfg.NodeView, res *ipnstate.PingResult, cb func(*ipnstate.PingResult)) { func (e *userspaceEngine) sendICMPEchoRequest(destIP netip.Addr, peer tailcfg.NodeView, res *ipnstate.PingResult, cb func(*ipnstate.PingResult)) {
@ -1366,8 +1368,9 @@ func (e *userspaceEngine) PeerForIP(ip netip.Addr) (ret PeerForIP, ok bool) {
} }
} }
} }
for _, a := range nm.Addresses { addrs := nm.GetAddresses()
if a.Addr() == ip && a.IsSingleIP() && tsaddr.IsTailscaleIP(ip) { for i := range addrs.LenIter() {
if a := addrs.At(i); a.Addr() == ip && a.IsSingleIP() && tsaddr.IsTailscaleIP(ip) {
return PeerForIP{Node: nm.SelfNode, IsSelf: true, Route: a}, true return PeerForIP{Node: nm.SelfNode, IsSelf: true, Route: a}, true
} }
} }

@ -56,7 +56,7 @@ func WGCfg(nm *netmap.NetworkMap, logf logger.Logf, flags netmap.WGConfigFlags,
cfg := &wgcfg.Config{ cfg := &wgcfg.Config{
Name: "tailscale", Name: "tailscale",
PrivateKey: nm.PrivateKey, PrivateKey: nm.PrivateKey,
Addresses: nm.Addresses, Addresses: nm.GetAddresses().AsSlice(),
Peers: make([]wgcfg.Peer, 0, len(nm.Peers)), Peers: make([]wgcfg.Peer, 0, len(nm.Peers)),
} }

Loading…
Cancel
Save