Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>main
parent
dbca186a64
commit
322499473e
@ -0,0 +1,172 @@ |
||||
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package ipnstate captures the entire state of the Tailscale network.
|
||||
//
|
||||
// It's a leaf package so ipn, wgengine, and magicsock can all depend on it.
|
||||
package ipnstate |
||||
|
||||
import ( |
||||
"bytes" |
||||
"log" |
||||
"sort" |
||||
"sync" |
||||
"time" |
||||
|
||||
"tailscale.com/tailcfg" |
||||
"tailscale.com/types/key" |
||||
) |
||||
|
||||
// Status represents the entire state of the IPN network.
|
||||
type Status struct { |
||||
BackendState string |
||||
Peer map[key.Public]*PeerStatus |
||||
User map[tailcfg.UserID]tailcfg.UserProfile |
||||
} |
||||
|
||||
func (s *Status) Peers() []key.Public { |
||||
kk := make([]key.Public, 0, len(s.Peer)) |
||||
for k := range s.Peer { |
||||
kk = append(kk, k) |
||||
} |
||||
sort.Slice(kk, func(i, j int) bool { return bytes.Compare(kk[i][:], kk[j][:]) < 0 }) |
||||
return kk |
||||
} |
||||
|
||||
type PeerStatus struct { |
||||
PublicKey key.Public |
||||
HostName string // HostInfo's Hostname (not a DNS name or necessarily unique)
|
||||
OS string // HostInfo.OS
|
||||
UserID tailcfg.UserID |
||||
|
||||
TailAddr string // Tailscale IP
|
||||
|
||||
// Endpoints:
|
||||
Addrs []string |
||||
CurAddr string // one of Addrs, or unique if roaming
|
||||
|
||||
RxBytes int64 |
||||
TxBytes int64 |
||||
Created time.Time // time registered with tailcontrol
|
||||
LastSeen time.Time // last seen to tailcontrol
|
||||
LastHandshake time.Time // with local wireguard
|
||||
KeepAlive bool |
||||
|
||||
// InNetworkMap means that this peer was seen in our latest network map.
|
||||
// In theory, all of InNetworkMap and InMagicSock and InEngine should all be true.
|
||||
InNetworkMap bool |
||||
|
||||
// InMagicSock means that this peer is being tracked by magicsock.
|
||||
// In theory, all of InNetworkMap and InMagicSock and InEngine should all be true.
|
||||
InMagicSock bool |
||||
|
||||
// InEngine means that this peer is tracked by the wireguard engine.
|
||||
// In theory, all of InNetworkMap and InMagicSock and InEngine should all be true.
|
||||
InEngine bool |
||||
} |
||||
|
||||
type StatusBuilder struct { |
||||
mu sync.Mutex |
||||
locked bool |
||||
st Status |
||||
} |
||||
|
||||
func (sb *StatusBuilder) Status() *Status { |
||||
sb.mu.Lock() |
||||
defer sb.mu.Unlock() |
||||
sb.locked = true |
||||
return &sb.st |
||||
} |
||||
|
||||
// AddUser adds a user profile to the status.
|
||||
func (sb *StatusBuilder) AddUser(id tailcfg.UserID, up tailcfg.UserProfile) { |
||||
sb.mu.Lock() |
||||
defer sb.mu.Unlock() |
||||
if sb.locked { |
||||
log.Printf("[unexpected] ipnstate: AddUser after Locked") |
||||
return |
||||
} |
||||
|
||||
if sb.st.User == nil { |
||||
sb.st.User = make(map[tailcfg.UserID]tailcfg.UserProfile) |
||||
} |
||||
|
||||
sb.st.User[id] = up |
||||
} |
||||
|
||||
// AddPeer adds a peer node to the status.
|
||||
//
|
||||
// Its PeerStatus is mixed with any previous status already added.
|
||||
func (sb *StatusBuilder) AddPeer(peer key.Public, st *PeerStatus) { |
||||
if st == nil { |
||||
panic("nil PeerStatus") |
||||
} |
||||
|
||||
sb.mu.Lock() |
||||
defer sb.mu.Unlock() |
||||
if sb.locked { |
||||
log.Printf("[unexpected] ipnstate: AddPeer after Locked") |
||||
return |
||||
} |
||||
|
||||
if sb.st.Peer == nil { |
||||
sb.st.Peer = make(map[key.Public]*PeerStatus) |
||||
} |
||||
e, ok := sb.st.Peer[peer] |
||||
if !ok { |
||||
sb.st.Peer[peer] = st |
||||
st.PublicKey = peer |
||||
return |
||||
} |
||||
|
||||
if v := st.HostName; v != "" { |
||||
e.HostName = v |
||||
} |
||||
if v := st.UserID; v != 0 { |
||||
e.UserID = v |
||||
} |
||||
if v := st.TailAddr; v != "" { |
||||
e.TailAddr = v |
||||
} |
||||
if v := st.OS; v != "" { |
||||
e.OS = st.OS |
||||
} |
||||
if v := st.Addrs; v != nil { |
||||
e.Addrs = v |
||||
} |
||||
if v := st.CurAddr; v != "" { |
||||
e.CurAddr = v |
||||
} |
||||
if v := st.RxBytes; v != 0 { |
||||
e.RxBytes = v |
||||
} |
||||
if v := st.TxBytes; v != 0 { |
||||
e.TxBytes = v |
||||
} |
||||
if v := st.LastHandshake; !v.IsZero() { |
||||
e.LastHandshake = v |
||||
} |
||||
if v := st.Created; !v.IsZero() { |
||||
e.Created = v |
||||
} |
||||
if v := st.LastSeen; !v.IsZero() { |
||||
e.LastSeen = v |
||||
} |
||||
if st.InNetworkMap { |
||||
e.InNetworkMap = true |
||||
} |
||||
if st.InMagicSock { |
||||
e.InMagicSock = true |
||||
} |
||||
if st.InEngine { |
||||
e.InEngine = true |
||||
} |
||||
if st.KeepAlive { |
||||
e.KeepAlive = true |
||||
} |
||||
} |
||||
|
||||
type StatusUpdater interface { |
||||
UpdateStatus(*StatusBuilder) |
||||
} |
||||
Loading…
Reference in new issue