diff --git a/cmd/tsconnect/wasm/wasm_js.go b/cmd/tsconnect/wasm/wasm_js.go index 9556fe043..bdcd749fe 100644 --- a/cmd/tsconnect/wasm/wasm_js.go +++ b/cmd/tsconnect/wasm/wasm_js.go @@ -37,6 +37,7 @@ import ( "tailscale.com/safesocket" "tailscale.com/tailcfg" "tailscale.com/tsd" + "tailscale.com/types/views" "tailscale.com/wgengine" "tailscale.com/wgengine/netstack" "tailscale.com/words" @@ -249,7 +250,7 @@ func (i *jsIPN) run(jsCallbacks js.Value) { Self: jsNetMapSelfNode{ jsNetMapNode: jsNetMapNode{ 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(), MachineKey: nm.MachineKey.String(), }, @@ -578,6 +579,14 @@ func mapSlice[T any, M any](a []T, f func(T) M) []M { 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 { n := make([]T, 0, len(a)) for _, e := range a { diff --git a/control/controlclient/map.go b/control/controlclient/map.go index 136ac5003..7a71dd29f 100644 --- a/control/controlclient/map.go +++ b/control/controlclient/map.go @@ -752,12 +752,6 @@ func (ms *mapSession) netmap() *netmap.NetworkMap { nm.SelfNode = node nm.Expiry = node.KeyExpiry() 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()) diff --git a/ipn/ipnlocal/dnsconfig_test.go b/ipn/ipnlocal/dnsconfig_test.go index 944ea7252..dbb40cd76 100644 --- a/ipn/ipnlocal/dnsconfig_test.go +++ b/ipn/ipnlocal/dnsconfig_test.go @@ -69,8 +69,10 @@ func TestDNSConfigForNetmap(t *testing.T) { { name: "self_name_and_peers", nm: &netmap.NetworkMap{ - Name: "myname.net", - Addresses: ipps("100.101.101.101"), + Name: "myname.net", + SelfNode: (&tailcfg.Node{ + Addresses: ipps("100.101.101.101"), + }).View(), }, peers: nodeViews([]*tailcfg.Node{ { @@ -106,8 +108,10 @@ func TestDNSConfigForNetmap(t *testing.T) { // even if they have IPv4. name: "v6_only_self", nm: &netmap.NetworkMap{ - Name: "myname.net", - Addresses: ipps("fe75::1"), + Name: "myname.net", + SelfNode: (&tailcfg.Node{ + Addresses: ipps("fe75::1"), + }).View(), }, peers: nodeViews([]*tailcfg.Node{ { @@ -141,8 +145,10 @@ func TestDNSConfigForNetmap(t *testing.T) { { name: "extra_records", nm: &netmap.NetworkMap{ - Name: "myname.net", - Addresses: ipps("100.101.101.101"), + Name: "myname.net", + SelfNode: (&tailcfg.Node{ + Addresses: ipps("100.101.101.101"), + }).View(), DNS: tailcfg.DNSConfig{ ExtraRecords: []tailcfg.DNSRecord{ {Name: "foo.com", Value: "1.2.3.4"}, diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index ab22c8c8f..d2000c6ac 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -2411,13 +2411,13 @@ func (b *LocalBackend) setAtomicValuesFromPrefsLocked(p ipn.PrefsView) { b.sshAtomicBool.Store(p.Valid() && p.RunSSH() && envknob.CanSSHD()) if !p.Valid() { - b.containsViaIPFuncAtomic.Store(tsaddr.NewContainsIPFunc(nil)) + b.containsViaIPFuncAtomic.Store(tsaddr.FalseContainsIPFunc()) b.setTCPPortsIntercepted(nil) b.lastServeConfJSON = mem.B(nil) b.serveConfig = ipn.ServeConfigView{} } else { filtered := tsaddr.FilterPrefixesCopy(p.AdvertiseRoutes(), tsaddr.IsViaPrefix) - b.containsViaIPFuncAtomic.Store(tsaddr.NewContainsIPFunc(filtered)) + b.containsViaIPFuncAtomic.Store(tsaddr.NewContainsIPFunc(views.SliceOf(filtered))) 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 := slices.ContainsFunc(nm.Addresses, tsaddr.PrefixIs6) && - !slices.ContainsFunc(nm.Addresses, tsaddr.PrefixIs4) + selfV6Only := views.SliceContainsFunc(nm.GetAddresses(), tsaddr.PrefixIs6) && + !views.SliceContainsFunc(nm.GetAddresses(), tsaddr.PrefixIs4) dcfg.OnlyIPv6 = selfV6Only // 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 } - set(nm.Name, views.SliceOf(nm.Addresses)) + set(nm.Name, nm.GetAddresses()) for _, peer := range peers { set(peer.Name(), peer.Addresses()) } @@ -4595,7 +4595,9 @@ func peerAPIBase(nm *netmap.NetworkMap, peer tailcfg.NodeView) string { } var have4, have6 bool - for _, a := range nm.Addresses { + addrs := nm.GetAddresses() + for i := range addrs.LenIter() { + a := addrs.At(i) if !a.IsSingleIP() { continue } diff --git a/ipn/ipnlocal/local_test.go b/ipn/ipnlocal/local_test.go index 7cb7a2ea6..a55b6f638 100644 --- a/ipn/ipnlocal/local_test.go +++ b/ipn/ipnlocal/local_test.go @@ -279,9 +279,11 @@ func TestPeerAPIBase(t *testing.T) { { name: "self_only_4_them_both", nm: &netmap.NetworkMap{ - Addresses: []netip.Prefix{ - netip.MustParsePrefix("100.64.1.1/32"), - }, + SelfNode: (&tailcfg.Node{ + Addresses: []netip.Prefix{ + netip.MustParsePrefix("100.64.1.1/32"), + }, + }).View(), }, peer: &tailcfg.Node{ Addresses: []netip.Prefix{ @@ -300,9 +302,11 @@ func TestPeerAPIBase(t *testing.T) { { name: "self_only_6_them_both", nm: &netmap.NetworkMap{ - Addresses: []netip.Prefix{ - netip.MustParsePrefix("fe70::1/128"), - }, + SelfNode: (&tailcfg.Node{ + Addresses: []netip.Prefix{ + netip.MustParsePrefix("fe70::1/128"), + }, + }).View(), }, peer: &tailcfg.Node{ Addresses: []netip.Prefix{ @@ -321,10 +325,12 @@ func TestPeerAPIBase(t *testing.T) { { name: "self_both_them_only_4", nm: &netmap.NetworkMap{ - Addresses: []netip.Prefix{ - netip.MustParsePrefix("100.64.1.1/32"), - netip.MustParsePrefix("fe70::1/128"), - }, + SelfNode: (&tailcfg.Node{ + Addresses: []netip.Prefix{ + netip.MustParsePrefix("100.64.1.1/32"), + netip.MustParsePrefix("fe70::1/128"), + }, + }).View(), }, peer: &tailcfg.Node{ Addresses: []netip.Prefix{ @@ -342,10 +348,12 @@ func TestPeerAPIBase(t *testing.T) { { name: "self_both_them_only_6", nm: &netmap.NetworkMap{ - Addresses: []netip.Prefix{ - netip.MustParsePrefix("100.64.1.1/32"), - netip.MustParsePrefix("fe70::1/128"), - }, + SelfNode: (&tailcfg.Node{ + Addresses: []netip.Prefix{ + netip.MustParsePrefix("100.64.1.1/32"), + netip.MustParsePrefix("fe70::1/128"), + }, + }).View(), }, peer: &tailcfg.Node{ Addresses: []netip.Prefix{ @@ -363,10 +371,12 @@ func TestPeerAPIBase(t *testing.T) { { name: "self_both_them_no_peerapi_service", nm: &netmap.NetworkMap{ - Addresses: []netip.Prefix{ - netip.MustParsePrefix("100.64.1.1/32"), - netip.MustParsePrefix("fe70::1/128"), - }, + SelfNode: (&tailcfg.Node{ + Addresses: []netip.Prefix{ + netip.MustParsePrefix("100.64.1.1/32"), + netip.MustParsePrefix("fe70::1/128"), + }, + }).View(), }, peer: &tailcfg.Node{ Addresses: []netip.Prefix{ @@ -689,10 +699,9 @@ func TestStatusWithoutPeers(t *testing.T) { b.Start(ipn.Options{}) b.Login(nil) cc.send(nil, "", false, &netmap.NetworkMap{ - MachineStatus: tailcfg.MachineAuthorized, - Addresses: ipps("100.101.101.101"), SelfNode: (&tailcfg.Node{ - Addresses: ipps("100.101.101.101"), + MachineAuthorized: true, + Addresses: ipps("100.101.101.101"), }).View(), }) got := b.StatusWithoutPeers() diff --git a/ipn/ipnlocal/state_test.go b/ipn/ipnlocal/state_test.go index 53c94ee6f..193c43909 100644 --- a/ipn/ipnlocal/state_test.go +++ b/ipn/ipnlocal/state_test.go @@ -501,7 +501,7 @@ func TestStateMachine(t *testing.T) { // (ie. I suspect it would be better to change false->true in send() // below, and do the same in the real controlclient.) cc.send(nil, "", false, &netmap.NetworkMap{ - MachineStatus: tailcfg.MachineAuthorized, + SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(), }) { nn := notifies.drain(1) @@ -665,7 +665,7 @@ func TestStateMachine(t *testing.T) { cc.persist.UserProfile.LoginName = "user2" cc.persist.NodeID = "node2" cc.send(nil, "", true, &netmap.NetworkMap{ - MachineStatus: tailcfg.MachineAuthorized, + SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(), }) { nn := notifies.drain(3) @@ -732,7 +732,7 @@ func TestStateMachine(t *testing.T) { t.Logf("\n\nStart4 -> netmap") notifies.expect(0) cc.send(nil, "", true, &netmap.NetworkMap{ - MachineStatus: tailcfg.MachineAuthorized, + SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(), }) { notifies.drain(0) @@ -801,7 +801,7 @@ func TestStateMachine(t *testing.T) { cc.persist.UserProfile.LoginName = "user3" cc.persist.NodeID = "node3" cc.send(nil, "", true, &netmap.NetworkMap{ - MachineStatus: tailcfg.MachineAuthorized, + SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(), }) { nn := notifies.drain(3) @@ -845,7 +845,7 @@ func TestStateMachine(t *testing.T) { t.Logf("\n\nLoginFinished5") notifies.expect(2) cc.send(nil, "", true, &netmap.NetworkMap{ - MachineStatus: tailcfg.MachineAuthorized, + SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(), }) { nn := notifies.drain(2) @@ -862,8 +862,8 @@ func TestStateMachine(t *testing.T) { t.Logf("\n\nExpireKey") notifies.expect(1) cc.send(nil, "", false, &netmap.NetworkMap{ - Expiry: time.Now().Add(-time.Minute), - MachineStatus: tailcfg.MachineAuthorized, + Expiry: time.Now().Add(-time.Minute), + SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(), }) { nn := notifies.drain(1) @@ -877,8 +877,8 @@ func TestStateMachine(t *testing.T) { t.Logf("\n\nExtendKey") notifies.expect(1) cc.send(nil, "", false, &netmap.NetworkMap{ - Expiry: time.Now().Add(time.Minute), - MachineStatus: tailcfg.MachineAuthorized, + Expiry: time.Now().Add(time.Minute), + SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(), }) { nn := notifies.drain(1) @@ -1023,7 +1023,7 @@ func TestWGEngineStatusRace(t *testing.T) { // Assert that we are logged in and authorized. cc.send(nil, "", true, &netmap.NetworkMap{ - MachineStatus: tailcfg.MachineAuthorized, + SelfNode: (&tailcfg.Node{MachineAuthorized: true}).View(), }) wantState(ipn.Starting) diff --git a/net/tsaddr/tsaddr.go b/net/tsaddr/tsaddr.go index 6319e30f4..088ff35e1 100644 --- a/net/tsaddr/tsaddr.go +++ b/net/tsaddr/tsaddr.go @@ -161,6 +161,11 @@ type oncePrefix struct { 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. // // It's optimized for the cases of addrs being empty and addrs @@ -168,20 +173,17 @@ type oncePrefix struct { // one IPv6 address). // // 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 // (or just IPv6), and both IPv4 and IPv6. - if len(addrs) == 0 { + if addrs.Len() == 0 { return func(netip.Addr) bool { return false } } // If any addr is more than a single IP, then just do the slow // linear thing until // https://github.com/inetaf/netaddr/issues/139 is done. - for _, a := range addrs { - if a.IsSingleIP() { - continue - } - acopy := append([]netip.Prefix(nil), addrs...) + if views.SliceContainsFunc(addrs, func(p netip.Prefix) bool { return !p.IsSingleIP() }) { + acopy := addrs.AsSlice() return func(ip netip.Addr) bool { for _, a := range acopy { 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: - if len(addrs) == 1 { - a := addrs[0] + if addrs.Len() == 1 { + a := addrs.At(0) return func(ip netip.Addr) bool { return ip == a.Addr() } } - if len(addrs) == 2 { - a, b := addrs[0], addrs[1] + if addrs.Len() == 2 { + a, b := addrs.At(0), addrs.At(1) return func(ip netip.Addr) bool { return ip == a.Addr() || ip == b.Addr() } } // General case: m := map[netip.Addr]bool{} - for _, a := range addrs { - m[a.Addr()] = true + for i := range addrs.LenIter() { + m[addrs.At(i).Addr()] = true } return func(ip netip.Addr) bool { return m[ip] } } diff --git a/net/tsaddr/tsaddr_test.go b/net/tsaddr/tsaddr_test.go index e74502005..7cc1a3881 100644 --- a/net/tsaddr/tsaddr_test.go +++ b/net/tsaddr/tsaddr_test.go @@ -8,6 +8,7 @@ import ( "testing" "tailscale.com/net/netaddr" + "tailscale.com/types/views" ) func TestInCrostiniRange(t *testing.T) { @@ -66,29 +67,29 @@ func TestCGNATRange(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")) { t.Fatal("bad") } if !f(netip.MustParseAddr("10.1.2.3")) { 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")) { t.Fatal("bad") } - f = NewContainsIPFunc([]netip.Prefix{ + f = NewContainsIPFunc(views.SliceOf([]netip.Prefix{ netip.MustParsePrefix("10.1.2.3/32"), netip.MustParsePrefix("::2/128"), - }) + })) if !f(netip.MustParseAddr("::2")) { 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.4/32"), netip.MustParsePrefix("::2/128"), - }) + })) if !f(netip.MustParseAddr("10.1.2.4")) { t.Fatal("bad") } diff --git a/net/tsdial/dnsmap_test.go b/net/tsdial/dnsmap_test.go index 33eda8b59..43461a135 100644 --- a/net/tsdial/dnsmap_test.go +++ b/net/tsdial/dnsmap_test.go @@ -32,10 +32,12 @@ func TestDNSMapFromNetworkMap(t *testing.T) { name: "self", nm: &netmap.NetworkMap{ Name: "foo.tailnet", - Addresses: []netip.Prefix{ - pfx("100.102.103.104/32"), - pfx("100::123/128"), - }, + SelfNode: (&tailcfg.Node{ + Addresses: []netip.Prefix{ + pfx("100.102.103.104/32"), + pfx("100::123/128"), + }, + }).View(), }, want: dnsMap{ "foo": ip("100.102.103.104"), @@ -46,10 +48,12 @@ func TestDNSMapFromNetworkMap(t *testing.T) { name: "self_and_peers", nm: &netmap.NetworkMap{ Name: "foo.tailnet", - Addresses: []netip.Prefix{ - pfx("100.102.103.104/32"), - pfx("100::123/128"), - }, + SelfNode: (&tailcfg.Node{ + Addresses: []netip.Prefix{ + pfx("100.102.103.104/32"), + pfx("100::123/128"), + }, + }).View(), Peers: []tailcfg.NodeView{ (&tailcfg.Node{ Name: "a.tailnet", @@ -79,9 +83,11 @@ func TestDNSMapFromNetworkMap(t *testing.T) { name: "self_has_v6_only", nm: &netmap.NetworkMap{ Name: "foo.tailnet", - Addresses: []netip.Prefix{ - pfx("100::123/128"), - }, + SelfNode: (&tailcfg.Node{ + Addresses: []netip.Prefix{ + pfx("100::123/128"), + }, + }).View(), Peers: nodeViews([]*tailcfg.Node{ { Name: "a.tailnet", diff --git a/types/netmap/netmap.go b/types/netmap/netmap.go index df950401d..a3570ff74 100644 --- a/types/netmap/netmap.go +++ b/types/netmap/netmap.go @@ -33,20 +33,6 @@ type NetworkMap struct { // It is the MapResponse.Node.Name value and ends with a period. 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 Peers []tailcfg.NodeView // sorted by Node.ID @@ -104,12 +90,6 @@ func (nm *NetworkMap) User() tailcfg.UserID { // if SelfNode is invalid. func (nm *NetworkMap) GetAddresses() 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() { return zero } @@ -128,12 +108,6 @@ func (nm *NetworkMap) AnyPeersAdvertiseRoutes() bool { // GetMachineStatus returns the MachineStatus of the local node. 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() { return tailcfg.MachineUnknown } @@ -258,25 +232,17 @@ func (nm *NetworkMap) printConciseHeader(buf *strings.Builder) { } } fmt.Fprintf(buf, " u=%s", login) - fmt.Fprintf(buf, " %v", nm.Addresses) + fmt.Fprintf(buf, " %v", nm.GetAddresses().AsSlice()) buf.WriteByte('\n') } // equalConciseHeader reports whether a and b are equal for the fields // used by printConciseHeader. func (a *NetworkMap) equalConciseHeader(b *NetworkMap) bool { - if a.NodeKey != b.NodeKey || - a.GetMachineStatus() != b.GetMachineStatus() || - a.User() != b.User() || - len(a.Addresses) != len(b.Addresses) { - return false - } - for i, a := range a.Addresses { - if b.Addresses[i] != a { - return false - } - } - return true + return a.NodeKey == b.NodeKey && + a.GetMachineStatus() == b.GetMachineStatus() && + a.User() == b.User() && + views.SliceEqual(a.GetAddresses(), b.GetAddresses()) } // printPeerConcise appends to buf a line representing the peer p. diff --git a/wgengine/magicsock/magicsock_test.go b/wgengine/magicsock/magicsock_test.go index 7700f6ca8..970483f56 100644 --- a/wgengine/magicsock/magicsock_test.go +++ b/wgengine/magicsock/magicsock_test.go @@ -274,7 +274,9 @@ func meshStacks(logf logger.Logf, mutateNetmap func(idx int, nm *netmap.NetworkM nm := &netmap.NetworkMap{ PrivateKey: me.privateKey, 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 { if i == myIdx { @@ -2267,7 +2269,9 @@ func TestIsWireGuardOnlyPeer(t *testing.T) { Name: "ts", PrivateKey: m.privateKey, NodeKey: m.privateKey.Public(), - Addresses: []netip.Prefix{tsaip}, + SelfNode: (&tailcfg.Node{ + Addresses: []netip.Prefix{tsaip}, + }).View(), Peers: nodeViews([]*tailcfg.Node{ { ID: 1, @@ -2326,7 +2330,9 @@ func TestIsWireGuardOnlyPeerWithMasquerade(t *testing.T) { Name: "ts", PrivateKey: m.privateKey, NodeKey: m.privateKey.Public(), - Addresses: []netip.Prefix{tsaip}, + SelfNode: (&tailcfg.Node{ + Addresses: []netip.Prefix{tsaip}, + }).View(), Peers: nodeViews([]*tailcfg.Node{ { ID: 1, @@ -2453,7 +2459,9 @@ func TestIsWireGuardOnlyPickEndpointByPing(t *testing.T) { Name: "ts", PrivateKey: m.privateKey, NodeKey: m.privateKey.Public(), - Addresses: []netip.Prefix{tsaip}, + SelfNode: (&tailcfg.Node{ + Addresses: []netip.Prefix{tsaip}, + }).View(), Peers: nodeViews([]*tailcfg.Node{ { Key: wgkey.Public(), diff --git a/wgengine/netstack/netstack.go b/wgengine/netstack/netstack.go index d0fe23169..e2f930b4c 100644 --- a/wgengine/netstack/netstack.go +++ b/wgengine/netstack/netstack.go @@ -221,7 +221,7 @@ func Create(logf logger.Logf, tundev *tstun.Wrapper, e wgengine.Engine, mc *magi dns: dns, } 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.PreFilterPacketOutboundToWireGuardNetstackIntercept = ns.handleLocalPackets return ns, nil @@ -324,10 +324,10 @@ var v4broadcast = netaddr.IPv4(255, 255, 255, 255) func (ns *Impl) UpdateNetstackIPs(nm *netmap.NetworkMap) { var selfNode tailcfg.NodeView if nm != nil { - ns.atomicIsLocalIPFunc.Store(tsaddr.NewContainsIPFunc(nm.Addresses)) + ns.atomicIsLocalIPFunc.Store(tsaddr.NewContainsIPFunc(nm.GetAddresses())) selfNode = nm.SelfNode } else { - ns.atomicIsLocalIPFunc.Store(tsaddr.NewContainsIPFunc(nil)) + ns.atomicIsLocalIPFunc.Store(tsaddr.FalseContainsIPFunc()) } oldIPs := make(map[tcpip.AddressWithPrefix]bool) diff --git a/wgengine/userspace.go b/wgengine/userspace.go index 8f59b2faf..c90a4b2be 100644 --- a/wgengine/userspace.go +++ b/wgengine/userspace.go @@ -286,8 +286,8 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error) return nil, err } } - e.isLocalAddr.Store(tsaddr.NewContainsIPFunc(nil)) - e.isDNSIPOverTailscale.Store(tsaddr.NewContainsIPFunc(nil)) + e.isLocalAddr.Store(tsaddr.FalseContainsIPFunc()) + e.isDNSIPOverTailscale.Store(tsaddr.FalseContainsIPFunc()) if conf.NetMon != nil { e.netMon = conf.NetMon @@ -782,7 +782,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config, 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() 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 // put that in the *dns.Config instead, and plumb it down to the // 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. // 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) { + var zero netip.Addr e.mu.Lock() defer e.mu.Unlock() if e.netMap == nil { - return netip.Addr{}, errors.New("no netmap") + return zero, errors.New("no netmap") } - for _, a := range e.netMap.Addresses { - if a.IsSingleIP() && a.Addr().BitLen() == dst.BitLen() { + addrs := e.netMap.GetAddresses() + 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 } } - if len(e.netMap.Addresses) == 0 { - return netip.Addr{}, errors.New("no self address in netmap") - } - return netip.Addr{}, errors.New("no self address in netmap matching address family") + return zero, 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)) { @@ -1366,8 +1368,9 @@ func (e *userspaceEngine) PeerForIP(ip netip.Addr) (ret PeerForIP, ok bool) { } } } - for _, a := range nm.Addresses { - if a.Addr() == ip && a.IsSingleIP() && tsaddr.IsTailscaleIP(ip) { + addrs := nm.GetAddresses() + 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 } } diff --git a/wgengine/wgcfg/nmcfg/nmcfg.go b/wgengine/wgcfg/nmcfg/nmcfg.go index 35ec23304..c64992524 100644 --- a/wgengine/wgcfg/nmcfg/nmcfg.go +++ b/wgengine/wgcfg/nmcfg/nmcfg.go @@ -56,7 +56,7 @@ func WGCfg(nm *netmap.NetworkMap, logf logger.Logf, flags netmap.WGConfigFlags, cfg := &wgcfg.Config{ Name: "tailscale", PrivateKey: nm.PrivateKey, - Addresses: nm.Addresses, + Addresses: nm.GetAddresses().AsSlice(), Peers: make([]wgcfg.Peer, 0, len(nm.Peers)), }