tools: Tailscale status

This commit is contained in:
世界
2026-04-09 19:34:27 +08:00
parent cfcc766d74
commit 5e7e58f5e9
10 changed files with 988 additions and 100 deletions

View File

@@ -0,0 +1,92 @@
//go:build with_gvisor
package tailscale
import (
"context"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/tailscale/ipn"
"github.com/sagernet/tailscale/ipn/ipnstate"
"github.com/sagernet/tailscale/tailcfg"
)
var _ adapter.TailscaleStatusProvider = (*Endpoint)(nil)
func (t *Endpoint) SubscribeTailscaleStatus(ctx context.Context, fn func(*adapter.TailscaleEndpointStatus)) error {
localBackend := t.server.ExportLocalBackend()
sendStatus := func() {
status := localBackend.Status()
fn(convertTailscaleStatus(status))
}
sendStatus()
localBackend.WatchNotifications(ctx, ipn.NotifyInitialState|ipn.NotifyInitialNetMap|ipn.NotifyRateLimit, nil, func(roNotify *ipn.Notify) (keepGoing bool) {
select {
case <-ctx.Done():
return false
default:
}
if roNotify.State != nil || roNotify.NetMap != nil || roNotify.BrowseToURL != nil {
sendStatus()
}
return true
})
return ctx.Err()
}
func convertTailscaleStatus(status *ipnstate.Status) *adapter.TailscaleEndpointStatus {
result := &adapter.TailscaleEndpointStatus{
BackendState: status.BackendState,
AuthURL: status.AuthURL,
}
if status.CurrentTailnet != nil {
result.NetworkName = status.CurrentTailnet.Name
result.MagicDNSSuffix = status.CurrentTailnet.MagicDNSSuffix
}
if status.Self != nil {
result.Self = convertTailscalePeer(status.Self)
}
result.Users = make(map[int64]*adapter.TailscaleUser, len(status.User))
for userID, profile := range status.User {
result.Users[int64(userID)] = convertTailscaleUser(userID, profile)
}
result.Peers = make([]*adapter.TailscalePeer, 0, len(status.Peer))
for _, peer := range status.Peer {
result.Peers = append(result.Peers, convertTailscalePeer(peer))
}
return result
}
func convertTailscalePeer(peer *ipnstate.PeerStatus) *adapter.TailscalePeer {
ips := make([]string, len(peer.TailscaleIPs))
for i, ip := range peer.TailscaleIPs {
ips[i] = ip.String()
}
var keyExpiry int64
if peer.KeyExpiry != nil {
keyExpiry = peer.KeyExpiry.Unix()
}
return &adapter.TailscalePeer{
HostName: peer.HostName,
DNSName: peer.DNSName,
OS: peer.OS,
TailscaleIPs: ips,
Online: peer.Online,
ExitNode: peer.ExitNode,
ExitNodeOption: peer.ExitNodeOption,
Active: peer.Active,
RxBytes: peer.RxBytes,
TxBytes: peer.TxBytes,
UserID: int64(peer.UserID),
KeyExpiry: keyExpiry,
}
}
func convertTailscaleUser(id tailcfg.UserID, profile tailcfg.UserProfile) *adapter.TailscaleUser {
return &adapter.TailscaleUser{
ID: int64(id),
LoginName: profile.LoginName,
DisplayName: profile.DisplayName,
ProfilePicURL: profile.ProfilePicURL,
}
}