Files
tslink/core/peer_status.go
T

83 lines
1.6 KiB
Go

package core
import (
"context"
"fmt"
"net"
"net/netip"
"sync"
"time"
"tailscale.com/ipn/ipnstate"
"tailscale.com/tsnet"
)
var statusCache struct {
mu sync.Mutex
status *ipnstate.Status
expires time.Time
}
const statusCacheTTL = 5 * time.Second
func getCachedStatus(ctx context.Context, srv *tsnet.Server) (*ipnstate.Status, error) {
statusCache.mu.Lock()
if statusCache.status != nil && time.Now().Before(statusCache.expires) {
st := statusCache.status
statusCache.mu.Unlock()
return st, nil
}
statusCache.mu.Unlock()
lc, err := srv.LocalClient()
if err != nil {
return nil, err
}
st, err := lc.Status(ctx)
if err != nil {
return nil, err
}
statusCache.mu.Lock()
statusCache.status = st
statusCache.expires = time.Now().Add(statusCacheTTL)
statusCache.mu.Unlock()
return st, nil
}
func isTsnetTarget(host string) bool {
if ip, err := netip.ParseAddr(host); err == nil {
tsnetV4 := netip.MustParsePrefix("100.64.0.0/10")
tsnetV6 := netip.MustParsePrefix("fd7a:115c:a1e0::/48")
return tsnetV4.Contains(ip) || tsnetV6.Contains(ip)
}
return true
}
func getConnType(ctx context.Context, srv *tsnet.Server, remoteAddrStr string) string {
st, err := getCachedStatus(ctx, srv)
if err != nil {
return "unknown"
}
remoteHost, _, err := net.SplitHostPort(remoteAddrStr)
if err != nil {
return "unknown"
}
for _, peer := range st.Peer {
for _, addr := range peer.TailscaleIPs {
if addr.String() == remoteHost {
if peer.CurAddr != "" {
return "direct"
}
if peer.Relay != "" {
return fmt.Sprintf("derp(%s)", peer.Relay)
}
return "direct"
}
}
}
return "unknown"
}