mirror of
https://github.com/tailscale/tailscale.git
synced 2025-07-31 16:23:44 +00:00
client/local, feature/relayserver, net/udprelay: move session status to its own package
Signed-off-by: Dylan Bargatze <dylan@tailscale.com>
This commit is contained in:
parent
2705d80902
commit
70569bb937
@ -35,7 +35,7 @@ import (
|
|||||||
"tailscale.com/ipn"
|
"tailscale.com/ipn"
|
||||||
"tailscale.com/ipn/ipnstate"
|
"tailscale.com/ipn/ipnstate"
|
||||||
"tailscale.com/net/netutil"
|
"tailscale.com/net/netutil"
|
||||||
"tailscale.com/net/udprelay/endpoint"
|
"tailscale.com/net/udprelay/status"
|
||||||
"tailscale.com/paths"
|
"tailscale.com/paths"
|
||||||
"tailscale.com/safesocket"
|
"tailscale.com/safesocket"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
@ -1641,12 +1641,12 @@ func (lc *Client) DebugSetExpireIn(ctx context.Context, d time.Duration) error {
|
|||||||
|
|
||||||
// DebugPeerRelaySessions returns debug information about the current peer
|
// DebugPeerRelaySessions returns debug information about the current peer
|
||||||
// relay sessions running through this node.
|
// relay sessions running through this node.
|
||||||
func (lc *Client) DebugPeerRelaySessions(ctx context.Context) ([]endpoint.PeerRelayServerSession, error) {
|
func (lc *Client) DebugPeerRelaySessions(ctx context.Context) ([]status.ServerSession, error) {
|
||||||
body, err := lc.send(ctx, "GET", "/localapi/v0/debug-peer-relay-sessions", 200, nil)
|
body, err := lc.send(ctx, "GET", "/localapi/v0/debug-peer-relay-sessions", 200, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error %w: %s", err, body)
|
return nil, fmt.Errorf("error %w: %s", err, body)
|
||||||
}
|
}
|
||||||
return decodeJSON[[]endpoint.PeerRelayServerSession](body)
|
return decodeJSON[[]status.ServerSession](body)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StreamDebugCapture streams a pcap-formatted packet capture.
|
// StreamDebugCapture streams a pcap-formatted packet capture.
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"tailscale.com/ipn/localapi"
|
"tailscale.com/ipn/localapi"
|
||||||
"tailscale.com/net/udprelay"
|
"tailscale.com/net/udprelay"
|
||||||
"tailscale.com/net/udprelay/endpoint"
|
"tailscale.com/net/udprelay/endpoint"
|
||||||
|
"tailscale.com/net/udprelay/status"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
@ -120,7 +121,7 @@ type extension struct {
|
|||||||
type relayServer interface {
|
type relayServer interface {
|
||||||
AllocateEndpoint(discoA key.DiscoPublic, discoB key.DiscoPublic) (endpoint.ServerEndpoint, error)
|
AllocateEndpoint(discoA key.DiscoPublic, discoB key.DiscoPublic) (endpoint.ServerEndpoint, error)
|
||||||
Close() error
|
Close() error
|
||||||
GetSessions() ([]endpoint.PeerRelayServerSession, error)
|
GetSessions() ([]status.ServerSession, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
// TODO (dylan): doc comments
|
||||||
@ -128,7 +129,7 @@ type PeerRelaySessionsReq struct{}
|
|||||||
|
|
||||||
// TODO (dylan): doc comments
|
// TODO (dylan): doc comments
|
||||||
type PeerRelaySessionsResp struct {
|
type PeerRelaySessionsResp struct {
|
||||||
Sessions []endpoint.PeerRelayServerSession
|
Sessions []status.ServerSession
|
||||||
Error error
|
Error error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,216 +62,3 @@ type ServerEndpoint struct {
|
|||||||
// bidirectional data flow.
|
// bidirectional data flow.
|
||||||
SteadyStateLifetime tstime.GoDuration
|
SteadyStateLifetime tstime.GoDuration
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
|
||||||
type PeerRelayServerAllocStatus int
|
|
||||||
|
|
||||||
const (
|
|
||||||
EndpointAllocNotStarted PeerRelayServerAllocStatus = iota
|
|
||||||
// EndpointAllocRequestReceived by the peer relay server from the allocating client
|
|
||||||
EndpointAllocRequestReceived
|
|
||||||
// EndpointAllocated on the peer relay server, but response not yet sent to allocating client
|
|
||||||
EndpointAllocated
|
|
||||||
// EndpointAllocResponseSent from the peer relay server to allocating client
|
|
||||||
EndpointAllocResponseSent
|
|
||||||
|
|
||||||
// TODO (dylan): Should we have a status here for dead allocs that weren't bound before the
|
|
||||||
// BindLifetime timer expired?
|
|
||||||
EndpointAllocExpired
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s PeerRelayServerAllocStatus) String() string {
|
|
||||||
switch s {
|
|
||||||
case EndpointAllocNotStarted:
|
|
||||||
return "alloc not started"
|
|
||||||
case EndpointAllocRequestReceived:
|
|
||||||
return "alloc request received"
|
|
||||||
case EndpointAllocated:
|
|
||||||
return "endpoint allocated"
|
|
||||||
case EndpointAllocResponseSent:
|
|
||||||
return "alloc complete"
|
|
||||||
case EndpointAllocExpired:
|
|
||||||
return "expired"
|
|
||||||
default:
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PeerRelayServerBindStatus is the current status of the endpoint binding
|
|
||||||
// handshake between the peer relay server and a SINGLE peer relay client. Both
|
|
||||||
// clients need to bind into an endpoint for a peer relay session to be bound,
|
|
||||||
// so a peer relay server will have two PeerRelayServerBindStatus fields to
|
|
||||||
// track per session.
|
|
||||||
type PeerRelayServerBindStatus int
|
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
|
||||||
const (
|
|
||||||
EndpointBindNotStarted PeerRelayServerBindStatus = iota
|
|
||||||
EndpointBindRequestReceived
|
|
||||||
EndpointBindChallengeSent
|
|
||||||
EndpointBindAnswerReceived
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s PeerRelayServerBindStatus) String() string {
|
|
||||||
switch s {
|
|
||||||
case EndpointBindNotStarted:
|
|
||||||
return "binding not started"
|
|
||||||
case EndpointBindRequestReceived:
|
|
||||||
return "bind request received"
|
|
||||||
case EndpointBindChallengeSent:
|
|
||||||
return "bind challenge sent"
|
|
||||||
case EndpointBindAnswerReceived:
|
|
||||||
return "bind complete"
|
|
||||||
default:
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PeerRelayServerPingStatus is the current status of a SINGLE SIDE of the
|
|
||||||
// bidirectional disco ping exchange between two peer relay clients, as seen by
|
|
||||||
// the peer relay server. As each client will send a disco ping and should
|
|
||||||
// receive a disco pong from the other client in response, a peer relay server
|
|
||||||
// will have two PeerRelayServerPingStatus fields to track per session.
|
|
||||||
type PeerRelayServerPingStatus int
|
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
|
||||||
const (
|
|
||||||
DiscoPingNotStarted PeerRelayServerPingStatus = iota
|
|
||||||
DiscoPingSeen
|
|
||||||
DiscoPongSeen
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s PeerRelayServerPingStatus) String() string {
|
|
||||||
switch s {
|
|
||||||
case DiscoPingNotStarted:
|
|
||||||
return "ping not started"
|
|
||||||
case DiscoPingSeen:
|
|
||||||
return "disco ping seen"
|
|
||||||
case DiscoPongSeen:
|
|
||||||
return "disco pong seen"
|
|
||||||
default:
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
|
||||||
type PeerRelayServerStatus int
|
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
|
||||||
const (
|
|
||||||
AllocatingEndpoint PeerRelayServerStatus = iota
|
|
||||||
BindingEndpoint
|
|
||||||
BidirectionalPinging
|
|
||||||
ServerSessionEstablished
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s PeerRelayServerStatus) String() string {
|
|
||||||
switch s {
|
|
||||||
case AllocatingEndpoint:
|
|
||||||
return "allocating endpoint allocation"
|
|
||||||
case BindingEndpoint:
|
|
||||||
return "binding endpoint"
|
|
||||||
case BidirectionalPinging:
|
|
||||||
return "clients pinging"
|
|
||||||
case ServerSessionEstablished:
|
|
||||||
return "session established"
|
|
||||||
default:
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
|
||||||
type PeerRelayServerSessionStatus struct {
|
|
||||||
AllocStatus PeerRelayServerAllocStatus
|
|
||||||
ClientBindStatus [2]PeerRelayServerBindStatus
|
|
||||||
ClientPingStatus [2]PeerRelayServerPingStatus
|
|
||||||
ClientPacketsRx [2]uint64
|
|
||||||
ClientPacketsFwd [2]uint64
|
|
||||||
|
|
||||||
OverallStatus PeerRelayServerStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPeerRelayServerSessionStatus() PeerRelayServerSessionStatus {
|
|
||||||
return PeerRelayServerSessionStatus{
|
|
||||||
AllocStatus: EndpointAllocNotStarted,
|
|
||||||
ClientBindStatus: [2]PeerRelayServerBindStatus{EndpointBindNotStarted, EndpointBindNotStarted},
|
|
||||||
ClientPingStatus: [2]PeerRelayServerPingStatus{DiscoPingNotStarted, DiscoPingNotStarted},
|
|
||||||
OverallStatus: AllocatingEndpoint,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
|
||||||
type PeerRelayClientAllocStatus int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// EndpointAllocRequestSent from the allocating client to the peer relay server via DERP
|
|
||||||
EndpointAllocRequestSent PeerRelayClientAllocStatus = iota
|
|
||||||
// EndpointAllocResponseReceived by the allocating client from the peer relay server via DERP
|
|
||||||
EndpointAllocResponseReceived
|
|
||||||
// CallMeMaybeViaSent from the allocating client to the target client via DERP
|
|
||||||
CallMeMaybeViaSent
|
|
||||||
// CallMeMaybeViaReceived by the target client from the allocating client via DERP
|
|
||||||
CallMeMaybeViaReceived
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
|
||||||
type PeerRelayClientBindStatus int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// EndpointBindHandshakeSent from this client to the peer relay server
|
|
||||||
EndpointBindHandshakeSent PeerRelayClientBindStatus = iota
|
|
||||||
// EndpointBindChallengeReceived by this client from the peer relay server
|
|
||||||
EndpointBindChallengeReceived
|
|
||||||
// EndpointBindAnswerSent from this client to the peer relay server
|
|
||||||
EndpointBindAnswerSent
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
|
||||||
type PeerRelayClientPingStatus int
|
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
|
||||||
const (
|
|
||||||
DiscoPingSent PeerRelayClientPingStatus = iota
|
|
||||||
DiscoPingReceived
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
|
||||||
type PeerRelayClientStatus int
|
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
|
||||||
const (
|
|
||||||
EndpointAllocation PeerRelayClientStatus = iota
|
|
||||||
EndpointBinding
|
|
||||||
Pinging
|
|
||||||
ClientSessionEstablished
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
|
||||||
type PeerRelayClientSessionStatus struct {
|
|
||||||
AllocStatus PeerRelayClientAllocStatus
|
|
||||||
BindStatus PeerRelayClientBindStatus
|
|
||||||
PingStatus PeerRelayClientPingStatus
|
|
||||||
|
|
||||||
OverallStatus PeerRelayClientStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
|
||||||
type PeerRelaySessionBaseStatus struct {
|
|
||||||
VNI uint32
|
|
||||||
ClientShortDisco [2]string
|
|
||||||
ClientEndpoint [2]netip.AddrPort
|
|
||||||
ServerShortDisco string
|
|
||||||
ServerEndpoint netip.AddrPort
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
|
||||||
type PeerRelayServerSession struct {
|
|
||||||
Status PeerRelayServerSessionStatus
|
|
||||||
PeerRelaySessionBaseStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO (dylan): doc comments
|
|
||||||
type PeerRelayClientSession struct {
|
|
||||||
Status PeerRelayClientStatus
|
|
||||||
PeerRelaySessionBaseStatus
|
|
||||||
}
|
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"tailscale.com/net/packet"
|
"tailscale.com/net/packet"
|
||||||
"tailscale.com/net/stun"
|
"tailscale.com/net/stun"
|
||||||
"tailscale.com/net/udprelay/endpoint"
|
"tailscale.com/net/udprelay/endpoint"
|
||||||
|
"tailscale.com/net/udprelay/status"
|
||||||
"tailscale.com/tstime"
|
"tailscale.com/tstime"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
@ -95,7 +96,7 @@ type serverEndpoint struct {
|
|||||||
vni uint32
|
vni uint32
|
||||||
allocatedAt time.Time
|
allocatedAt time.Time
|
||||||
|
|
||||||
status endpoint.PeerRelayServerSessionStatus
|
status status.SessionStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *serverEndpoint) handleDiscoControlMsg(from netip.AddrPort, senderIndex int, discoMsg disco.Message, conn *net.UDPConn, serverDisco key.DiscoPublic) {
|
func (e *serverEndpoint) handleDiscoControlMsg(from netip.AddrPort, senderIndex int, discoMsg disco.Message, conn *net.UDPConn, serverDisco key.DiscoPublic) {
|
||||||
@ -137,7 +138,7 @@ func (e *serverEndpoint) handleDiscoControlMsg(from netip.AddrPort, senderIndex
|
|||||||
e.handshakeAddrPorts[senderIndex] = from
|
e.handshakeAddrPorts[senderIndex] = from
|
||||||
// TODO (dylan): assert current e.status.AllocStatus is EndpointAllocated
|
// TODO (dylan): assert current e.status.AllocStatus is EndpointAllocated
|
||||||
// TODO (dylan): assert e.status.ClientBindStatus[senderIndex] is not already EndpointBindRequestReceived or later
|
// TODO (dylan): assert e.status.ClientBindStatus[senderIndex] is not already EndpointBindRequestReceived or later
|
||||||
e.status.ClientBindStatus[senderIndex] = endpoint.EndpointBindRequestReceived
|
e.status.ClientBindStatus[senderIndex] = status.EndpointBindRequestReceived
|
||||||
m := new(disco.BindUDPRelayEndpointChallenge)
|
m := new(disco.BindUDPRelayEndpointChallenge)
|
||||||
m.VNI = e.vni
|
m.VNI = e.vni
|
||||||
m.Generation = discoMsg.Generation
|
m.Generation = discoMsg.Generation
|
||||||
@ -155,8 +156,8 @@ func (e *serverEndpoint) handleDiscoControlMsg(from netip.AddrPort, senderIndex
|
|||||||
box := e.discoSharedSecrets[senderIndex].Seal(m.AppendMarshal(nil))
|
box := e.discoSharedSecrets[senderIndex].Seal(m.AppendMarshal(nil))
|
||||||
reply = append(reply, box...)
|
reply = append(reply, box...)
|
||||||
conn.WriteMsgUDPAddrPort(reply, nil, from)
|
conn.WriteMsgUDPAddrPort(reply, nil, from)
|
||||||
e.status.ClientBindStatus[senderIndex] = endpoint.EndpointBindChallengeSent
|
e.status.ClientBindStatus[senderIndex] = status.EndpointBindChallengeSent
|
||||||
e.status.OverallStatus = endpoint.BindingEndpoint
|
e.status.OverallStatus = status.Binding
|
||||||
return
|
return
|
||||||
case *disco.BindUDPRelayEndpointAnswer:
|
case *disco.BindUDPRelayEndpointAnswer:
|
||||||
err := validateVNIAndRemoteKey(discoMsg.BindUDPRelayEndpointCommon)
|
err := validateVNIAndRemoteKey(discoMsg.BindUDPRelayEndpointCommon)
|
||||||
@ -176,11 +177,11 @@ func (e *serverEndpoint) handleDiscoControlMsg(from netip.AddrPort, senderIndex
|
|||||||
e.boundAddrPorts[senderIndex] = from
|
e.boundAddrPorts[senderIndex] = from
|
||||||
|
|
||||||
// TODO (dylan): assert e.status.AllocStatus is EndpointAllocated
|
// TODO (dylan): assert e.status.AllocStatus is EndpointAllocated
|
||||||
// TODO (dylan): assert e.status.ClientBindStatus[senderIndex] is endpoint.EndpointBindChallengeSent
|
// TODO (dylan): assert e.status.ClientBindStatus[senderIndex] is status.EndpointBindChallengeSent
|
||||||
// TODO (dylan): assert e.status.ClientBindStatus[senderIndex] is not already EndpointBindAnswerReceived or later
|
// TODO (dylan): assert e.status.ClientBindStatus[senderIndex] is not already EndpointBindAnswerReceived or later
|
||||||
e.status.ClientBindStatus[senderIndex] = endpoint.EndpointBindAnswerReceived
|
e.status.ClientBindStatus[senderIndex] = status.EndpointBindAnswerReceived
|
||||||
if e.isBound() {
|
if e.isBound() {
|
||||||
e.status.OverallStatus = endpoint.BidirectionalPinging
|
e.status.OverallStatus = status.Pinging
|
||||||
}
|
}
|
||||||
e.lastSeen[senderIndex] = time.Now() // record last seen as bound time
|
e.lastSeen[senderIndex] = time.Now() // record last seen as bound time
|
||||||
return
|
return
|
||||||
@ -237,10 +238,10 @@ func (e *serverEndpoint) handlePacket(from netip.AddrPort, gh packet.GeneveHeade
|
|||||||
to = e.boundAddrPorts[1]
|
to = e.boundAddrPorts[1]
|
||||||
e.status.ClientPacketsRx[0]++
|
e.status.ClientPacketsRx[0]++
|
||||||
switch e.status.ClientPingStatus[0] {
|
switch e.status.ClientPingStatus[0] {
|
||||||
case endpoint.DiscoPingNotStarted:
|
case status.DiscoPingNotStarted:
|
||||||
e.status.ClientPingStatus[0] = endpoint.DiscoPingSeen
|
e.status.ClientPingStatus[0] = status.DiscoPingSeen
|
||||||
case endpoint.DiscoPingSeen:
|
case status.DiscoPingSeen:
|
||||||
e.status.ClientPingStatus[0] = endpoint.DiscoPongSeen
|
e.status.ClientPingStatus[0] = status.DiscoPongSeen
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -250,10 +251,10 @@ func (e *serverEndpoint) handlePacket(from netip.AddrPort, gh packet.GeneveHeade
|
|||||||
to = e.boundAddrPorts[0]
|
to = e.boundAddrPorts[0]
|
||||||
e.status.ClientPacketsRx[1]++
|
e.status.ClientPacketsRx[1]++
|
||||||
switch e.status.ClientPingStatus[1] {
|
switch e.status.ClientPingStatus[1] {
|
||||||
case endpoint.DiscoPingNotStarted:
|
case status.DiscoPingNotStarted:
|
||||||
e.status.ClientPingStatus[1] = endpoint.DiscoPingSeen
|
e.status.ClientPingStatus[1] = status.DiscoPingSeen
|
||||||
case endpoint.DiscoPingSeen:
|
case status.DiscoPingSeen:
|
||||||
e.status.ClientPingStatus[1] = endpoint.DiscoPongSeen
|
e.status.ClientPingStatus[1] = status.DiscoPongSeen
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -263,8 +264,8 @@ func (e *serverEndpoint) handlePacket(from netip.AddrPort, gh packet.GeneveHeade
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.status.OverallStatus == endpoint.BidirectionalPinging && e.status.ClientPingStatus[0] == endpoint.DiscoPongSeen && e.status.ClientPingStatus[1] == endpoint.DiscoPongSeen {
|
if e.status.OverallStatus == status.Pinging && e.status.ClientPingStatus[0] == status.DiscoPongSeen && e.status.ClientPingStatus[1] == status.DiscoPongSeen {
|
||||||
e.status.OverallStatus = endpoint.ServerSessionEstablished
|
e.status.OverallStatus = status.Established
|
||||||
}
|
}
|
||||||
// Relay the packet towards the other party via the socket associated
|
// Relay the packet towards the other party via the socket associated
|
||||||
// with the destination's address family. If source and destination
|
// with the destination's address family. If source and destination
|
||||||
@ -680,13 +681,14 @@ func (s *Server) AllocateEndpoint(discoA, discoB key.DiscoPublic) (endpoint.Serv
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.lamportID++
|
s.lamportID++
|
||||||
status := endpoint.NewPeerRelayServerSessionStatus()
|
st := status.NewSessionStatus()
|
||||||
status.AllocStatus = endpoint.EndpointAllocRequestReceived
|
st.AllocStatus = status.EndpointAllocRequestReceived
|
||||||
|
st.OverallStatus = status.Allocating
|
||||||
e = &serverEndpoint{
|
e = &serverEndpoint{
|
||||||
discoPubKeys: pair,
|
discoPubKeys: pair,
|
||||||
lamportID: s.lamportID,
|
lamportID: s.lamportID,
|
||||||
allocatedAt: time.Now(),
|
allocatedAt: time.Now(),
|
||||||
status: status,
|
status: st,
|
||||||
}
|
}
|
||||||
e.discoSharedSecrets[0] = s.disco.Shared(e.discoPubKeys.Get()[0])
|
e.discoSharedSecrets[0] = s.disco.Shared(e.discoPubKeys.Get()[0])
|
||||||
e.discoSharedSecrets[1] = s.disco.Shared(e.discoPubKeys.Get()[1])
|
e.discoSharedSecrets[1] = s.disco.Shared(e.discoPubKeys.Get()[1])
|
||||||
@ -707,8 +709,9 @@ func (s *Server) AllocateEndpoint(discoA, discoB key.DiscoPublic) (endpoint.Serv
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) GetSessions() ([]endpoint.PeerRelayServerSession, error) {
|
// TODO (dylan): doc comments
|
||||||
var sessions = make([]endpoint.PeerRelayServerSession, 0)
|
func (s *Server) GetSessions() ([]status.ServerSession, error) {
|
||||||
|
var sessions = make([]status.ServerSession, 0)
|
||||||
for k, v := range s.byDisco {
|
for k, v := range s.byDisco {
|
||||||
var c1Ep, c2Ep netip.AddrPort
|
var c1Ep, c2Ep netip.AddrPort
|
||||||
|
|
||||||
@ -725,17 +728,15 @@ func (s *Server) GetSessions() ([]endpoint.PeerRelayServerSession, error) {
|
|||||||
} else if v.handshakeAddrPorts[1].IsValid() {
|
} else if v.handshakeAddrPorts[1].IsValid() {
|
||||||
c2Ep = v.handshakeAddrPorts[1]
|
c2Ep = v.handshakeAddrPorts[1]
|
||||||
}
|
}
|
||||||
sessions = append(sessions, endpoint.PeerRelayServerSession{
|
sessions = append(sessions, status.ServerSession{
|
||||||
// TODO (dylan): fix overall status
|
// TODO (dylan): fix overall status
|
||||||
Status: v.status,
|
Status: v.status,
|
||||||
PeerRelaySessionBaseStatus: endpoint.PeerRelaySessionBaseStatus{
|
VNI: v.vni,
|
||||||
VNI: v.vni,
|
ClientShortDisco: [2]string{c1Disco, c2Disco},
|
||||||
ClientShortDisco: [2]string{c1Disco, c2Disco},
|
ClientEndpoint: [2]netip.AddrPort{c1Ep, c2Ep},
|
||||||
ClientEndpoint: [2]netip.AddrPort{c1Ep, c2Ep},
|
ServerShortDisco: s.discoPublic.ShortString(),
|
||||||
ServerShortDisco: s.discoPublic.ShortString(),
|
// TODO (dylan): disambiguate which addrPort to use here
|
||||||
// TODO (dylan): disambiguate which addrPort to use here
|
ServerEndpoint: s.addrPorts[0],
|
||||||
ServerEndpoint: s.addrPorts[0],
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return sessions, nil
|
return sessions, nil
|
||||||
|
184
net/udprelay/status/status.go
Normal file
184
net/udprelay/status/status.go
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
// Package status contains types relating to the status of peer relay sessions
|
||||||
|
// between nodes via a peer relay server.
|
||||||
|
package status
|
||||||
|
|
||||||
|
import "net/netip"
|
||||||
|
|
||||||
|
// ServerSession contains status information for a single session between two
|
||||||
|
// peer relay clients relayed via a peer relay server. This is the status as
|
||||||
|
// seen by the peer relay server; each client node may have a different view of
|
||||||
|
// the session's current status.
|
||||||
|
type ServerSession struct {
|
||||||
|
// Status is the current state of the session, as seen by the peer relay
|
||||||
|
// server. It contains the status of each phase of session setup and usage:
|
||||||
|
// endpoint allocation, endpoint binding, disco ping/pong, and active.
|
||||||
|
// TODO (dylan): confirm these statuses/state machines
|
||||||
|
Status SessionStatus
|
||||||
|
// VNI is the Virtual Network Identifier for this peer relay session, which
|
||||||
|
// comes from the Geneve header and is unique to this session.
|
||||||
|
VNI uint32
|
||||||
|
// ClientShortDisco is a string representation of each peer relay client's
|
||||||
|
// disco public key (one string for each of the two clients).
|
||||||
|
// TODO (dylan): can either of these ever be nil?
|
||||||
|
ClientShortDisco [2]string
|
||||||
|
// ClientEndpoint is the [netip.AddrPort] of each peer relay client's
|
||||||
|
// endpoint participating in the session (one endpoint for each of the two
|
||||||
|
// clients).
|
||||||
|
// TODO (dylan): can either of these ever be nil?
|
||||||
|
ClientEndpoint [2]netip.AddrPort
|
||||||
|
// ServerShortDisco is a string representation of the peer relay server's
|
||||||
|
// disco public key.
|
||||||
|
// TODO (dylan): can there be a different disco key per-client?
|
||||||
|
ServerShortDisco string
|
||||||
|
// ServerEndpoint is the [netip.AddrPort] for the peer relay server's
|
||||||
|
// endpoint participating in the session (one endpoint for each of the two
|
||||||
|
// clients).
|
||||||
|
// TODO (dylan): can there be a different endpoint per-client?
|
||||||
|
ServerEndpoint netip.AddrPort
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO (dylan): doc comments
|
||||||
|
type SessionStatus struct {
|
||||||
|
AllocStatus AllocStatus
|
||||||
|
ClientBindStatus [2]BindStatus
|
||||||
|
ClientPingStatus [2]PingStatus
|
||||||
|
ClientPacketsRx [2]uint64
|
||||||
|
ClientPacketsFwd [2]uint64
|
||||||
|
|
||||||
|
OverallStatus OverallSessionStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO (dylan): doc comments
|
||||||
|
func NewSessionStatus() SessionStatus {
|
||||||
|
return SessionStatus{
|
||||||
|
AllocStatus: EndpointAllocNotStarted,
|
||||||
|
ClientBindStatus: [2]BindStatus{EndpointBindNotStarted, EndpointBindNotStarted},
|
||||||
|
ClientPingStatus: [2]PingStatus{DiscoPingNotStarted, DiscoPingNotStarted},
|
||||||
|
OverallStatus: Allocating,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO (dylan): doc comments
|
||||||
|
type AllocStatus int
|
||||||
|
|
||||||
|
// TODO (dylan): doc comments
|
||||||
|
const (
|
||||||
|
EndpointAllocNotStarted AllocStatus = iota
|
||||||
|
// EndpointAllocRequestReceived by the peer relay server from the allocating client
|
||||||
|
EndpointAllocRequestReceived
|
||||||
|
// EndpointAllocated on the peer relay server, but response not yet sent to allocating client
|
||||||
|
EndpointAllocated
|
||||||
|
// EndpointAllocResponseSent from the peer relay server to allocating client
|
||||||
|
EndpointAllocResponseSent
|
||||||
|
|
||||||
|
// TODO (dylan): Should we have a status here for dead allocs that weren't bound before the
|
||||||
|
// BindLifetime timer expired?
|
||||||
|
EndpointAllocExpired
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s AllocStatus) String() string {
|
||||||
|
switch s {
|
||||||
|
case EndpointAllocNotStarted:
|
||||||
|
return "alloc not started"
|
||||||
|
case EndpointAllocRequestReceived:
|
||||||
|
return "alloc request received"
|
||||||
|
case EndpointAllocated:
|
||||||
|
return "endpoint allocated"
|
||||||
|
case EndpointAllocResponseSent:
|
||||||
|
return "alloc complete"
|
||||||
|
case EndpointAllocExpired:
|
||||||
|
return "expired"
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindStatus is the current status of the endpoint binding handshake between
|
||||||
|
// the peer relay server and a SINGLE peer relay client. Both clients need to
|
||||||
|
// bind into an endpoint for a peer relay session to be bound, so a peer relay
|
||||||
|
// server will have two BindStatus fields to track per session.
|
||||||
|
type BindStatus int
|
||||||
|
|
||||||
|
// TODO (dylan): doc comments
|
||||||
|
const (
|
||||||
|
EndpointBindNotStarted BindStatus = iota
|
||||||
|
EndpointBindRequestReceived
|
||||||
|
EndpointBindChallengeSent
|
||||||
|
EndpointBindAnswerReceived
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s BindStatus) String() string {
|
||||||
|
switch s {
|
||||||
|
case EndpointBindNotStarted:
|
||||||
|
return "binding not started"
|
||||||
|
case EndpointBindRequestReceived:
|
||||||
|
return "bind request received"
|
||||||
|
case EndpointBindChallengeSent:
|
||||||
|
return "bind challenge sent"
|
||||||
|
case EndpointBindAnswerReceived:
|
||||||
|
return "bind complete"
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PingStatus is the current status of a SINGLE SIDE of the
|
||||||
|
// bidirectional disco ping exchange between two peer relay clients, as seen by
|
||||||
|
// the peer relay server. As each client will send a disco ping and should
|
||||||
|
// receive a disco pong from the other client in response, a peer relay server
|
||||||
|
// will have two PingStatus fields to track per session.
|
||||||
|
type PingStatus int
|
||||||
|
|
||||||
|
// TODO (dylan): doc comments
|
||||||
|
const (
|
||||||
|
DiscoPingNotStarted PingStatus = iota
|
||||||
|
DiscoPingSeen
|
||||||
|
DiscoPongSeen
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO (dylan): doc comments
|
||||||
|
func (s PingStatus) String() string {
|
||||||
|
switch s {
|
||||||
|
case DiscoPingNotStarted:
|
||||||
|
return "ping not started"
|
||||||
|
case DiscoPingSeen:
|
||||||
|
return "disco ping seen"
|
||||||
|
case DiscoPongSeen:
|
||||||
|
return "disco pong seen"
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO (dylan): doc comments
|
||||||
|
type OverallSessionStatus int
|
||||||
|
|
||||||
|
// TODO (dylan): doc comments
|
||||||
|
const (
|
||||||
|
NotStarted OverallSessionStatus = iota
|
||||||
|
Allocating
|
||||||
|
Binding
|
||||||
|
Pinging
|
||||||
|
Established
|
||||||
|
Idle
|
||||||
|
)
|
||||||
|
|
||||||
|
// String returns a short, human-readable string representation of the current
|
||||||
|
// [OverallSessionStatus].
|
||||||
|
func (s OverallSessionStatus) String() string {
|
||||||
|
switch s {
|
||||||
|
case Allocating:
|
||||||
|
return "allocating endpoint"
|
||||||
|
case Binding:
|
||||||
|
return "binding endpoint"
|
||||||
|
case Pinging:
|
||||||
|
return "clients pinging"
|
||||||
|
case Established:
|
||||||
|
return "session established"
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user