From 762180595d23fbe8c16920d65b24c3c6f449194a Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 14 Apr 2021 07:20:27 -0700 Subject: [PATCH] ipn/ipnstate: add PeerStatus.TailscaleIPs slice, deprecate TailAddr Signed-off-by: Brad Fitzpatrick --- cmd/tailscale/cli/ping.go | 5 ++++- cmd/tailscale/cli/status.go | 10 ++++++++- ipn/ipnlocal/local.go | 40 ++++++++++++++++++--------------- ipn/ipnstate/ipnstate.go | 22 +++++++++++++----- wgengine/magicsock/magicsock.go | 17 +++++++++----- 5 files changed, 63 insertions(+), 31 deletions(-) diff --git a/cmd/tailscale/cli/ping.go b/cmd/tailscale/cli/ping.go index ff9af7e78..be9261038 100644 --- a/cmd/tailscale/cli/ping.go +++ b/cmd/tailscale/cli/ping.go @@ -154,7 +154,10 @@ func tailscaleIPFromArg(ctx context.Context, hostOrIP string) (ip string, err er } for _, ps := range st.Peer { if hostOrIP == dnsOrQuoteHostname(st, ps) || hostOrIP == ps.DNSName { - return ps.TailAddr, nil + if len(ps.TailscaleIPs) == 0 { + return "", errors.New("node found but lacks an IP") + } + return ps.TailscaleIPs[0].String(), nil } } diff --git a/cmd/tailscale/cli/status.go b/cmd/tailscale/cli/status.go index 091db8bbc..af887f427 100644 --- a/cmd/tailscale/cli/status.go +++ b/cmd/tailscale/cli/status.go @@ -18,6 +18,7 @@ import ( "github.com/peterbourgon/ff/v2/ffcli" "github.com/toqueteos/webbrowser" + "inet.af/netaddr" "tailscale.com/client/tailscale" "tailscale.com/ipn" "tailscale.com/ipn/ipnstate" @@ -131,7 +132,7 @@ func runStatus(ctx context.Context, args []string) error { printPS := func(ps *ipnstate.PeerStatus) { active := peerActive(ps) f("%-15s %-20s %-12s %-7s ", - ps.TailAddr, + firstIPString(ps.TailscaleIPs), dnsOrQuoteHostname(st, ps), ownerLogin(st, ps), ps.OS, @@ -216,3 +217,10 @@ func ownerLogin(st *ipnstate.Status, ps *ipnstate.PeerStatus) string { } return u.LoginName } + +func firstIPString(v []netaddr.IP) string { + if len(v) == 0 { + return "" + } + return v[0].String() +} diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 67b2d02b9..a4c404f35 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -339,28 +339,32 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) { if p.LastSeen != nil { lastSeen = *p.LastSeen } - var tailAddr string + var tailAddr4 string + var tailscaleIPs = make([]netaddr.IP, 0, len(p.Addresses)) for _, addr := range p.Addresses { - // The peer struct currently only allows a single - // Tailscale IP address. For compatibility with the - // old display, make sure it's the IPv4 address. - if addr.IP.Is4() && addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.IP) { - tailAddr = addr.IP.String() - break + if addr.IsSingleIP() && tsaddr.IsTailscaleIP(addr.IP) { + if addr.IP.Is4() && tailAddr4 == "" { + // The peer struct previously only allowed a single + // Tailscale IP address. For compatibility for a few releases starting + // with 1.8, keep it pulled out as IPv4-only for a bit. + tailAddr4 = addr.IP.String() + } + tailscaleIPs = append(tailscaleIPs, addr.IP) } } sb.AddPeer(key.Public(p.Key), &ipnstate.PeerStatus{ - InNetworkMap: true, - UserID: p.User, - TailAddr: tailAddr, - HostName: p.Hostinfo.Hostname, - DNSName: p.Name, - OS: p.Hostinfo.OS, - KeepAlive: p.KeepAlive, - Created: p.Created, - LastSeen: lastSeen, - ShareeNode: p.Hostinfo.ShareeNode, - ExitNode: p.StableID != "" && p.StableID == b.prefs.ExitNodeID, + InNetworkMap: true, + UserID: p.User, + TailAddrDeprecated: tailAddr4, + TailscaleIPs: tailscaleIPs, + HostName: p.Hostinfo.Hostname, + DNSName: p.Name, + OS: p.Hostinfo.OS, + KeepAlive: p.KeepAlive, + Created: p.Created, + LastSeen: lastSeen, + ShareeNode: p.Hostinfo.ShareeNode, + ExitNode: p.StableID != "" && p.StableID == b.prefs.ExitNodeID, }) } } diff --git a/ipn/ipnstate/ipnstate.go b/ipn/ipnstate/ipnstate.go index c781718ae..a748f3271 100644 --- a/ipn/ipnstate/ipnstate.go +++ b/ipn/ipnstate/ipnstate.go @@ -71,7 +71,8 @@ type PeerStatus struct { OS string // HostInfo.OS UserID tailcfg.UserID - TailAddr string // Tailscale IP + TailAddrDeprecated string `json:"TailAddr"` // Tailscale IP + TailscaleIPs []netaddr.IP // Tailscale IP(s) assigned to this node // Endpoints: Addrs []string @@ -213,8 +214,11 @@ func (sb *StatusBuilder) AddPeer(peer key.Public, st *PeerStatus) { if v := st.UserID; v != 0 { e.UserID = v } - if v := st.TailAddr; v != "" { - e.TailAddr = v + if v := st.TailAddrDeprecated; v != "" { + e.TailAddrDeprecated = v + } + if v := st.TailscaleIPs; v != nil { + e.TailscaleIPs = v } if v := st.OS; v != "" { e.OS = st.OS @@ -343,13 +347,17 @@ table tbody tr:nth-child(even) td { background-color: #f5f5f5; } hostNameHTML = "
" + html.EscapeString(hostName) } + var tailAddr string + if len(ps.TailscaleIPs) > 0 { + tailAddr = ps.TailscaleIPs[0].String() + } f("%s%s"+ "%s%s
%s
%s%v%v%v", ps.PublicKey.ShortString(), osEmoji(ps.OS), html.EscapeString(dnsName), hostNameHTML, - ps.TailAddr, + tailAddr, html.EscapeString(owner), ps.RxBytes, ps.TxBytes, @@ -437,5 +445,9 @@ func sortKey(ps *PeerStatus) string { if ps.HostName != "" { return ps.HostName } - return ps.TailAddr + // TODO(bradfitz): add PeerStatus.Less and avoid these allocs in a Less func. + if len(ps.TailscaleIPs) > 0 { + return ps.TailscaleIPs[0].String() + } + return string(ps.PublicKey[:]) } diff --git a/wgengine/magicsock/magicsock.go b/wgengine/magicsock/magicsock.go index 2db796ea2..417f04dae 100644 --- a/wgengine/magicsock/magicsock.go +++ b/wgengine/magicsock/magicsock.go @@ -2953,19 +2953,23 @@ func (c *Conn) UpdateStatus(sb *ipnstate.StatusBuilder) { c.mu.Lock() defer c.mu.Unlock() - var tailAddr string + var tailAddr4 string + var tailscaleIPs []netaddr.IP if c.netMap != nil { + tailscaleIPs = make([]netaddr.IP, 0, len(c.netMap.Addresses)) for _, addr := range c.netMap.Addresses { if !addr.IsSingleIP() { continue } sb.AddTailscaleIP(addr.IP) - // TailAddr only allows for a single Tailscale IP. For - // readability of `tailscale status`, make it the IPv4 - // address. + // TailAddr previously only allowed for a + // single Tailscale IP. For compatibility for + // a couple releases starting with 1.8, keep + // that field pulled out separately. if addr.IP.Is4() { - tailAddr = addr.IP.String() + tailAddr4 = addr.IP.String() } + tailscaleIPs = append(tailscaleIPs, addr.IP) } } @@ -2989,7 +2993,8 @@ func (c *Conn) UpdateStatus(sb *ipnstate.StatusBuilder) { ss.Relay = derpRegion.RegionCode } } - ss.TailAddr = tailAddr + ss.TailscaleIPs = tailscaleIPs + ss.TailAddrDeprecated = tailAddr4 }) for dk, n := range c.nodeOfDisco {