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("