mirror of
https://github.com/coder/coder.git
synced 2025-07-15 22:20:27 +00:00
chore: add DRPC tailnet & cli network telemetry (#13687)
This commit is contained in:
@ -58,6 +58,9 @@ func (r *RootCmd) ping() *serpent.Command {
|
|||||||
_, _ = fmt.Fprintln(inv.Stderr, "Direct connections disabled.")
|
_, _ = fmt.Fprintln(inv.Stderr, "Direct connections disabled.")
|
||||||
opts.BlockEndpoints = true
|
opts.BlockEndpoints = true
|
||||||
}
|
}
|
||||||
|
if !r.disableNetworkTelemetry {
|
||||||
|
opts.EnableTelemetry = true
|
||||||
|
}
|
||||||
conn, err := workspacesdk.New(client).DialAgent(ctx, workspaceAgent.ID, opts)
|
conn, err := workspacesdk.New(client).DialAgent(ctx, workspaceAgent.ID, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -106,6 +106,9 @@ func (r *RootCmd) portForward() *serpent.Command {
|
|||||||
_, _ = fmt.Fprintln(inv.Stderr, "Direct connections disabled.")
|
_, _ = fmt.Fprintln(inv.Stderr, "Direct connections disabled.")
|
||||||
opts.BlockEndpoints = true
|
opts.BlockEndpoints = true
|
||||||
}
|
}
|
||||||
|
if !r.disableNetworkTelemetry {
|
||||||
|
opts.EnableTelemetry = true
|
||||||
|
}
|
||||||
conn, err := workspacesdk.New(client).DialAgent(ctx, workspaceAgent.ID, opts)
|
conn, err := workspacesdk.New(client).DialAgent(ctx, workspaceAgent.ID, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
39
cli/root.go
39
cli/root.go
@ -52,19 +52,20 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
varURL = "url"
|
varURL = "url"
|
||||||
varToken = "token"
|
varToken = "token"
|
||||||
varAgentToken = "agent-token"
|
varAgentToken = "agent-token"
|
||||||
varAgentTokenFile = "agent-token-file"
|
varAgentTokenFile = "agent-token-file"
|
||||||
varAgentURL = "agent-url"
|
varAgentURL = "agent-url"
|
||||||
varHeader = "header"
|
varHeader = "header"
|
||||||
varHeaderCommand = "header-command"
|
varHeaderCommand = "header-command"
|
||||||
varNoOpen = "no-open"
|
varNoOpen = "no-open"
|
||||||
varNoVersionCheck = "no-version-warning"
|
varNoVersionCheck = "no-version-warning"
|
||||||
varNoFeatureWarning = "no-feature-warning"
|
varNoFeatureWarning = "no-feature-warning"
|
||||||
varForceTty = "force-tty"
|
varForceTty = "force-tty"
|
||||||
varVerbose = "verbose"
|
varVerbose = "verbose"
|
||||||
varDisableDirect = "disable-direct-connections"
|
varDisableDirect = "disable-direct-connections"
|
||||||
|
varDisableNetworkTelemetry = "disable-network-telemetry"
|
||||||
|
|
||||||
notLoggedInMessage = "You are not logged in. Try logging in using 'coder login <url>'."
|
notLoggedInMessage = "You are not logged in. Try logging in using 'coder login <url>'."
|
||||||
|
|
||||||
@ -435,6 +436,13 @@ func (r *RootCmd) Command(subcommands []*serpent.Command) (*serpent.Command, err
|
|||||||
Value: serpent.BoolOf(&r.disableDirect),
|
Value: serpent.BoolOf(&r.disableDirect),
|
||||||
Group: globalGroup,
|
Group: globalGroup,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Flag: varDisableNetworkTelemetry,
|
||||||
|
Env: "CODER_DISABLE_NETWORK_TELEMETRY",
|
||||||
|
Description: "Disable network telemetry. Network telemetry is collected when connecting to workspaces using the CLI, and is forwarded to the server. If telemetry is also enabled on the server, it may be sent to Coder. Network telemetry is used to measure network quality and detect regressions.",
|
||||||
|
Value: serpent.BoolOf(&r.disableNetworkTelemetry),
|
||||||
|
Group: globalGroup,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Flag: "debug-http",
|
Flag: "debug-http",
|
||||||
Description: "Debug codersdk HTTP requests.",
|
Description: "Debug codersdk HTTP requests.",
|
||||||
@ -481,8 +489,9 @@ type RootCmd struct {
|
|||||||
disableDirect bool
|
disableDirect bool
|
||||||
debugHTTP bool
|
debugHTTP bool
|
||||||
|
|
||||||
noVersionCheck bool
|
disableNetworkTelemetry bool
|
||||||
noFeatureWarning bool
|
noVersionCheck bool
|
||||||
|
noFeatureWarning bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitClient authenticates the client with files from disk
|
// InitClient authenticates the client with files from disk
|
||||||
|
@ -102,6 +102,9 @@ func (r *RootCmd) speedtest() *serpent.Command {
|
|||||||
_, _ = fmt.Fprintln(inv.Stderr, "Direct connections disabled.")
|
_, _ = fmt.Fprintln(inv.Stderr, "Direct connections disabled.")
|
||||||
opts.BlockEndpoints = true
|
opts.BlockEndpoints = true
|
||||||
}
|
}
|
||||||
|
if !r.disableNetworkTelemetry {
|
||||||
|
opts.EnableTelemetry = true
|
||||||
|
}
|
||||||
if pcapFile != "" {
|
if pcapFile != "" {
|
||||||
s := capture.New()
|
s := capture.New()
|
||||||
opts.CaptureHook = s.LogPacket
|
opts.CaptureHook = s.LogPacket
|
||||||
@ -183,6 +186,7 @@ func (r *RootCmd) speedtest() *serpent.Command {
|
|||||||
outputResult.Intervals[i] = interval
|
outputResult.Intervals[i] = interval
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
conn.Conn.SendSpeedtestTelemetry(outputResult.Overall.ThroughputMbits)
|
||||||
out, err := formatter.Format(inv.Context(), outputResult)
|
out, err := formatter.Format(inv.Context(), outputResult)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -243,8 +243,9 @@ func (r *RootCmd) ssh() *serpent.Command {
|
|||||||
}
|
}
|
||||||
conn, err := workspacesdk.New(client).
|
conn, err := workspacesdk.New(client).
|
||||||
DialAgent(ctx, workspaceAgent.ID, &workspacesdk.DialAgentOptions{
|
DialAgent(ctx, workspaceAgent.ID, &workspacesdk.DialAgentOptions{
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
BlockEndpoints: r.disableDirect,
|
BlockEndpoints: r.disableDirect,
|
||||||
|
EnableTelemetry: !r.disableNetworkTelemetry,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("dial agent: %w", err)
|
return xerrors.Errorf("dial agent: %w", err)
|
||||||
@ -436,6 +437,7 @@ func (r *RootCmd) ssh() *serpent.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = sshSession.Wait()
|
err = sshSession.Wait()
|
||||||
|
conn.SendDisconnectedTelemetry("ssh")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if exitErr := (&gossh.ExitError{}); errors.As(err, &exitErr) {
|
if exitErr := (&gossh.ExitError{}); errors.As(err, &exitErr) {
|
||||||
// Clear the error since it's not useful beyond
|
// Clear the error since it's not useful beyond
|
||||||
|
7
cli/testdata/coder_--help.golden
vendored
7
cli/testdata/coder_--help.golden
vendored
@ -66,6 +66,13 @@ variables or flags.
|
|||||||
--disable-direct-connections bool, $CODER_DISABLE_DIRECT_CONNECTIONS
|
--disable-direct-connections bool, $CODER_DISABLE_DIRECT_CONNECTIONS
|
||||||
Disable direct (P2P) connections to workspaces.
|
Disable direct (P2P) connections to workspaces.
|
||||||
|
|
||||||
|
--disable-network-telemetry bool, $CODER_DISABLE_NETWORK_TELEMETRY
|
||||||
|
Disable network telemetry. Network telemetry is collected when
|
||||||
|
connecting to workspaces using the CLI, and is forwarded to the
|
||||||
|
server. If telemetry is also enabled on the server, it may be sent to
|
||||||
|
Coder. Network telemetry is used to measure network quality and detect
|
||||||
|
regressions.
|
||||||
|
|
||||||
--global-config string, $CODER_CONFIG_DIR (default: ~/.config/coderv2)
|
--global-config string, $CODER_CONFIG_DIR (default: ~/.config/coderv2)
|
||||||
Path to the global `coder` config directory.
|
Path to the global `coder` config directory.
|
||||||
|
|
||||||
|
@ -1163,9 +1163,9 @@ type Netcheck struct {
|
|||||||
IPv4 bool `json:"ipv4"`
|
IPv4 bool `json:"ipv4"`
|
||||||
IPv6CanSend bool `json:"ipv6_can_send"`
|
IPv6CanSend bool `json:"ipv6_can_send"`
|
||||||
IPv4CanSend bool `json:"ipv4_can_send"`
|
IPv4CanSend bool `json:"ipv4_can_send"`
|
||||||
OSHasIPv6 bool `json:"os_has_ipv6"`
|
|
||||||
ICMPv4 bool `json:"icmpv4"`
|
ICMPv4 bool `json:"icmpv4"`
|
||||||
|
|
||||||
|
OSHasIPv6 *bool `json:"os_has_ipv6"`
|
||||||
MappingVariesByDestIP *bool `json:"mapping_varies_by_dest_ip"`
|
MappingVariesByDestIP *bool `json:"mapping_varies_by_dest_ip"`
|
||||||
HairPinning *bool `json:"hair_pinning"`
|
HairPinning *bool `json:"hair_pinning"`
|
||||||
UPnP *bool `json:"upnp"`
|
UPnP *bool `json:"upnp"`
|
||||||
@ -1210,9 +1210,9 @@ func netcheckFromProto(proto *tailnetproto.Netcheck) Netcheck {
|
|||||||
IPv4: proto.IPv4,
|
IPv4: proto.IPv4,
|
||||||
IPv6CanSend: proto.IPv6CanSend,
|
IPv6CanSend: proto.IPv6CanSend,
|
||||||
IPv4CanSend: proto.IPv4CanSend,
|
IPv4CanSend: proto.IPv4CanSend,
|
||||||
OSHasIPv6: proto.OSHasIPv6,
|
|
||||||
ICMPv4: proto.ICMPv4,
|
ICMPv4: proto.ICMPv4,
|
||||||
|
|
||||||
|
OSHasIPv6: protoBool(proto.OSHasIPv6),
|
||||||
MappingVariesByDestIP: protoBool(proto.MappingVariesByDestIP),
|
MappingVariesByDestIP: protoBool(proto.MappingVariesByDestIP),
|
||||||
HairPinning: protoBool(proto.HairPinning),
|
HairPinning: protoBool(proto.HairPinning),
|
||||||
UPnP: protoBool(proto.UPnP),
|
UPnP: protoBool(proto.UPnP),
|
||||||
@ -1221,33 +1221,28 @@ func netcheckFromProto(proto *tailnetproto.Netcheck) Netcheck {
|
|||||||
|
|
||||||
PreferredDERP: proto.PreferredDERP,
|
PreferredDERP: proto.PreferredDERP,
|
||||||
|
|
||||||
RegionLatency: durationMapFromProto(proto.RegionLatency),
|
|
||||||
RegionV4Latency: durationMapFromProto(proto.RegionV4Latency),
|
RegionV4Latency: durationMapFromProto(proto.RegionV4Latency),
|
||||||
RegionV6Latency: durationMapFromProto(proto.RegionV6Latency),
|
RegionV6Latency: durationMapFromProto(proto.RegionV6Latency),
|
||||||
|
|
||||||
GlobalV4: netcheckIPFromProto(proto.GlobalV4),
|
GlobalV4: netcheckIPFromProto(proto.GlobalV4),
|
||||||
GlobalV6: netcheckIPFromProto(proto.GlobalV6),
|
GlobalV6: netcheckIPFromProto(proto.GlobalV6),
|
||||||
|
|
||||||
CaptivePortal: protoBool(proto.CaptivePortal),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetworkEvent and all related structs come from tailnet.proto.
|
// NetworkEvent and all related structs come from tailnet.proto.
|
||||||
type NetworkEvent struct {
|
type NetworkEvent struct {
|
||||||
ID uuid.UUID `json:"id"`
|
ID uuid.UUID `json:"id"`
|
||||||
Time time.Time `json:"time"`
|
Time time.Time `json:"time"`
|
||||||
Application string `json:"application"`
|
Application string `json:"application"`
|
||||||
Status string `json:"status"` // connected, disconnected
|
Status string `json:"status"` // connected, disconnected
|
||||||
DisconnectionReason string `json:"disconnection_reason"`
|
DisconnectionReason string `json:"disconnection_reason"`
|
||||||
ClientType string `json:"client_type"` // cli, agent, coderd, wsproxy
|
ClientType string `json:"client_type"` // cli, agent, coderd, wsproxy
|
||||||
NodeIDSelf uint64 `json:"node_id_self"`
|
NodeIDSelf uint64 `json:"node_id_self"`
|
||||||
NodeIDRemote uint64 `json:"node_id_remote"`
|
NodeIDRemote uint64 `json:"node_id_remote"`
|
||||||
P2PEndpoint NetworkEventP2PEndpoint `json:"p2p_endpoint"`
|
P2PEndpoint NetworkEventP2PEndpoint `json:"p2p_endpoint"`
|
||||||
LogIPHashes map[string]NetworkEventIPFields `json:"log_ip_hashes"`
|
HomeDERP string `json:"home_derp"`
|
||||||
HomeDERP string `json:"home_derp"`
|
DERPMap DERPMap `json:"derp_map"`
|
||||||
Logs []string `json:"logs"`
|
LatestNetcheck Netcheck `json:"latest_netcheck"`
|
||||||
DERPMap DERPMap `json:"derp_map"`
|
|
||||||
LatestNetcheck Netcheck `json:"latest_netcheck"`
|
|
||||||
|
|
||||||
ConnectionAge *time.Duration `json:"connection_age"`
|
ConnectionAge *time.Duration `json:"connection_age"`
|
||||||
ConnectionSetup *time.Duration `json:"connection_setup"`
|
ConnectionSetup *time.Duration `json:"connection_setup"`
|
||||||
@ -1281,11 +1276,6 @@ func NetworkEventFromProto(proto *tailnetproto.TelemetryEvent) (NetworkEvent, er
|
|||||||
return NetworkEvent{}, xerrors.Errorf("parse id %q: %w", proto.Id, err)
|
return NetworkEvent{}, xerrors.Errorf("parse id %q: %w", proto.Id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logIPHashes := make(map[string]NetworkEventIPFields, len(proto.LogIpHashes))
|
|
||||||
for k, v := range proto.LogIpHashes {
|
|
||||||
logIPHashes[k] = ipFieldsFromProto(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
return NetworkEvent{
|
return NetworkEvent{
|
||||||
ID: id,
|
ID: id,
|
||||||
Time: proto.Time.AsTime(),
|
Time: proto.Time.AsTime(),
|
||||||
@ -1296,9 +1286,7 @@ func NetworkEventFromProto(proto *tailnetproto.TelemetryEvent) (NetworkEvent, er
|
|||||||
NodeIDSelf: proto.NodeIdSelf,
|
NodeIDSelf: proto.NodeIdSelf,
|
||||||
NodeIDRemote: proto.NodeIdRemote,
|
NodeIDRemote: proto.NodeIdRemote,
|
||||||
P2PEndpoint: p2pEndpointFromProto(proto.P2PEndpoint),
|
P2PEndpoint: p2pEndpointFromProto(proto.P2PEndpoint),
|
||||||
LogIPHashes: logIPHashes,
|
|
||||||
HomeDERP: proto.HomeDerp,
|
HomeDERP: proto.HomeDerp,
|
||||||
Logs: proto.Logs,
|
|
||||||
DERPMap: derpMapFromProto(proto.DerpMap),
|
DERPMap: derpMapFromProto(proto.DerpMap),
|
||||||
LatestNetcheck: netcheckFromProto(proto.LatestNetcheck),
|
LatestNetcheck: netcheckFromProto(proto.LatestNetcheck),
|
||||||
|
|
||||||
|
@ -149,6 +149,7 @@ func (c *AgentConn) SSH(ctx context.Context) (*gonet.TCPConn, error) {
|
|||||||
return nil, xerrors.Errorf("workspace agent not reachable in time: %v", ctx.Err())
|
return nil, xerrors.Errorf("workspace agent not reachable in time: %v", ctx.Err())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.Conn.SendConnectedTelemetry(c.agentAddress(), tailnet.TelemetryApplicationSSH)
|
||||||
return c.Conn.DialContextTCP(ctx, netip.AddrPortFrom(c.agentAddress(), AgentSSHPort))
|
return c.Conn.DialContextTCP(ctx, netip.AddrPortFrom(c.agentAddress(), AgentSSHPort))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,6 +186,7 @@ func (c *AgentConn) Speedtest(ctx context.Context, direction speedtest.Direction
|
|||||||
return nil, xerrors.Errorf("workspace agent not reachable in time: %v", ctx.Err())
|
return nil, xerrors.Errorf("workspace agent not reachable in time: %v", ctx.Err())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.Conn.SendConnectedTelemetry(c.agentAddress(), tailnet.TelemetryApplicationSpeedtest)
|
||||||
speedConn, err := c.Conn.DialContextTCP(ctx, netip.AddrPortFrom(c.agentAddress(), AgentSpeedtestPort))
|
speedConn, err := c.Conn.DialContextTCP(ctx, netip.AddrPortFrom(c.agentAddress(), AgentSpeedtestPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("dial speedtest: %w", err)
|
return nil, xerrors.Errorf("dial speedtest: %w", err)
|
||||||
@ -378,3 +380,7 @@ func (c *AgentConn) apiClient() *http.Client {
|
|||||||
func (c *AgentConn) GetPeerDiagnostics() tailnet.PeerDiagnostics {
|
func (c *AgentConn) GetPeerDiagnostics() tailnet.PeerDiagnostics {
|
||||||
return c.Conn.GetPeerDiagnostics(c.opts.AgentID)
|
return c.Conn.GetPeerDiagnostics(c.opts.AgentID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *AgentConn) SendDisconnectedTelemetry(application string) {
|
||||||
|
c.Conn.SendDisconnectedTelemetry(c.agentAddress(), application)
|
||||||
|
}
|
||||||
|
@ -7,12 +7,16 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"slices"
|
"slices"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"nhooyr.io/websocket"
|
"nhooyr.io/websocket"
|
||||||
|
"storj.io/drpc"
|
||||||
|
"storj.io/drpc/drpcerr"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
|
|
||||||
"cdr.dev/slog"
|
"cdr.dev/slog"
|
||||||
@ -38,6 +42,7 @@ type tailnetConn interface {
|
|||||||
//
|
//
|
||||||
// 1) run the Coordinate API and pass node information back and forth
|
// 1) run the Coordinate API and pass node information back and forth
|
||||||
// 2) stream DERPMap updates and program the Conn
|
// 2) stream DERPMap updates and program the Conn
|
||||||
|
// 3) Send network telemetry events
|
||||||
//
|
//
|
||||||
// These functions share the same websocket, and so are combined here so that if we hit a problem
|
// These functions share the same websocket, and so are combined here so that if we hit a problem
|
||||||
// we tear the whole thing down and start over with a new websocket.
|
// we tear the whole thing down and start over with a new websocket.
|
||||||
@ -58,32 +63,32 @@ type tailnetAPIConnector struct {
|
|||||||
coordinateURL string
|
coordinateURL string
|
||||||
dialOptions *websocket.DialOptions
|
dialOptions *websocket.DialOptions
|
||||||
conn tailnetConn
|
conn tailnetConn
|
||||||
|
customDialFn func() (proto.DRPCTailnetClient, error)
|
||||||
|
|
||||||
|
clientMu sync.RWMutex
|
||||||
|
client proto.DRPCTailnetClient
|
||||||
|
|
||||||
connected chan error
|
connected chan error
|
||||||
isFirst bool
|
isFirst bool
|
||||||
closed chan struct{}
|
closed chan struct{}
|
||||||
|
|
||||||
|
// Only set to true if we get a response from the server that it doesn't support
|
||||||
|
// network telemetry.
|
||||||
|
telemetryUnavailable atomic.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// runTailnetAPIConnector creates and runs a tailnetAPIConnector
|
// Create a new tailnetAPIConnector without running it
|
||||||
func runTailnetAPIConnector(
|
func newTailnetAPIConnector(ctx context.Context, logger slog.Logger, agentID uuid.UUID, coordinateURL string, dialOptions *websocket.DialOptions) *tailnetAPIConnector {
|
||||||
ctx context.Context, logger slog.Logger,
|
return &tailnetAPIConnector{
|
||||||
agentID uuid.UUID, coordinateURL string, dialOptions *websocket.DialOptions,
|
|
||||||
conn tailnetConn,
|
|
||||||
) *tailnetAPIConnector {
|
|
||||||
tac := &tailnetAPIConnector{
|
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
agentID: agentID,
|
agentID: agentID,
|
||||||
coordinateURL: coordinateURL,
|
coordinateURL: coordinateURL,
|
||||||
dialOptions: dialOptions,
|
dialOptions: dialOptions,
|
||||||
conn: conn,
|
conn: nil,
|
||||||
connected: make(chan error, 1),
|
connected: make(chan error, 1),
|
||||||
closed: make(chan struct{}),
|
closed: make(chan struct{}),
|
||||||
}
|
}
|
||||||
tac.gracefulCtx, tac.cancelGracefulCtx = context.WithCancel(context.Background())
|
|
||||||
go tac.manageGracefulTimeout()
|
|
||||||
go tac.run()
|
|
||||||
return tac
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// manageGracefulTimeout allows the gracefulContext to last 1 second longer than the main context
|
// manageGracefulTimeout allows the gracefulContext to last 1 second longer than the main context
|
||||||
@ -99,21 +104,27 @@ func (tac *tailnetAPIConnector) manageGracefulTimeout() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tac *tailnetAPIConnector) run() {
|
// Runs a tailnetAPIConnector using the provided connection
|
||||||
tac.isFirst = true
|
func (tac *tailnetAPIConnector) runConnector(conn tailnetConn) {
|
||||||
defer close(tac.closed)
|
tac.conn = conn
|
||||||
for retrier := retry.New(50*time.Millisecond, 10*time.Second); retrier.Wait(tac.ctx); {
|
tac.gracefulCtx, tac.cancelGracefulCtx = context.WithCancel(context.Background())
|
||||||
tailnetClient, err := tac.dial()
|
go tac.manageGracefulTimeout()
|
||||||
if xerrors.Is(err, &codersdk.Error{}) {
|
go func() {
|
||||||
return
|
tac.isFirst = true
|
||||||
|
defer close(tac.closed)
|
||||||
|
for retrier := retry.New(50*time.Millisecond, 10*time.Second); retrier.Wait(tac.ctx); {
|
||||||
|
tailnetClient, err := tac.dial()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tac.clientMu.Lock()
|
||||||
|
tac.client = tailnetClient
|
||||||
|
tac.clientMu.Unlock()
|
||||||
|
tac.logger.Debug(tac.ctx, "obtained tailnet API v2+ client")
|
||||||
|
tac.coordinateAndDERPMap(tailnetClient)
|
||||||
|
tac.logger.Debug(tac.ctx, "tailnet API v2+ connection lost")
|
||||||
}
|
}
|
||||||
if err != nil {
|
}()
|
||||||
continue
|
|
||||||
}
|
|
||||||
tac.logger.Debug(tac.ctx, "obtained tailnet API v2+ client")
|
|
||||||
tac.coordinateAndDERPMap(tailnetClient)
|
|
||||||
tac.logger.Debug(tac.ctx, "tailnet API v2+ connection lost")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var permanentErrorStatuses = []int{
|
var permanentErrorStatuses = []int{
|
||||||
@ -123,6 +134,9 @@ var permanentErrorStatuses = []int{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tac *tailnetAPIConnector) dial() (proto.DRPCTailnetClient, error) {
|
func (tac *tailnetAPIConnector) dial() (proto.DRPCTailnetClient, error) {
|
||||||
|
if tac.customDialFn != nil {
|
||||||
|
return tac.customDialFn()
|
||||||
|
}
|
||||||
tac.logger.Debug(tac.ctx, "dialing Coder tailnet v2+ API")
|
tac.logger.Debug(tac.ctx, "dialing Coder tailnet v2+ API")
|
||||||
// nolint:bodyclose
|
// nolint:bodyclose
|
||||||
ws, res, err := websocket.Dial(tac.ctx, tac.coordinateURL, tac.dialOptions)
|
ws, res, err := websocket.Dial(tac.ctx, tac.coordinateURL, tac.dialOptions)
|
||||||
@ -194,7 +208,10 @@ func (tac *tailnetAPIConnector) coordinateAndDERPMap(client proto.DRPCTailnetCli
|
|||||||
// we do NOT want to gracefully disconnect on the coordinate() routine. So, we'll just
|
// we do NOT want to gracefully disconnect on the coordinate() routine. So, we'll just
|
||||||
// close the underlying connection. This will trigger a retry of the control plane in
|
// close the underlying connection. This will trigger a retry of the control plane in
|
||||||
// run().
|
// run().
|
||||||
|
tac.clientMu.Lock()
|
||||||
client.DRPCConn().Close()
|
client.DRPCConn().Close()
|
||||||
|
tac.client = nil
|
||||||
|
tac.clientMu.Unlock()
|
||||||
// Note that derpMap() logs it own errors, we don't bother here.
|
// Note that derpMap() logs it own errors, we don't bother here.
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -258,3 +275,22 @@ func (tac *tailnetAPIConnector) derpMap(client proto.DRPCTailnetClient) error {
|
|||||||
tac.conn.SetDERPMap(dm)
|
tac.conn.SetDERPMap(dm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tac *tailnetAPIConnector) SendTelemetryEvent(event *proto.TelemetryEvent) {
|
||||||
|
tac.clientMu.RLock()
|
||||||
|
// We hold the lock for the entire telemetry request, but this would only block
|
||||||
|
// a coordinate retry, and closing the connection.
|
||||||
|
defer tac.clientMu.RUnlock()
|
||||||
|
if tac.client == nil || tac.telemetryUnavailable.Load() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(tac.ctx, 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
_, err := tac.client.PostTelemetry(ctx, &proto.TelemetryRequest{
|
||||||
|
Events: []*proto.TelemetryEvent{event},
|
||||||
|
})
|
||||||
|
if drpcerr.Code(err) == drpcerr.Unimplemented || drpc.ProtocolError.Has(err) && strings.Contains(err.Error(), "unknown rpc: ") {
|
||||||
|
tac.logger.Debug(tac.ctx, "attempted to send telemetry to a server that doesn't support it", slog.Error(err))
|
||||||
|
tac.telemetryUnavailable.Store(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,7 +13,10 @@ import (
|
|||||||
"github.com/hashicorp/yamux"
|
"github.com/hashicorp/yamux"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
"nhooyr.io/websocket"
|
"nhooyr.io/websocket"
|
||||||
|
"storj.io/drpc"
|
||||||
|
"storj.io/drpc/drpcerr"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
|
|
||||||
"cdr.dev/slog"
|
"cdr.dev/slog"
|
||||||
@ -75,7 +78,8 @@ func TestTailnetAPIConnector_Disconnects(t *testing.T) {
|
|||||||
|
|
||||||
fConn := newFakeTailnetConn()
|
fConn := newFakeTailnetConn()
|
||||||
|
|
||||||
uut := runTailnetAPIConnector(ctx, logger, agentID, svr.URL, &websocket.DialOptions{}, fConn)
|
uut := newTailnetAPIConnector(ctx, logger, agentID, svr.URL, &websocket.DialOptions{})
|
||||||
|
uut.runConnector(fConn)
|
||||||
|
|
||||||
call := testutil.RequireRecvCtx(ctx, t, fCoord.CoordinateCalls)
|
call := testutil.RequireRecvCtx(ctx, t, fCoord.CoordinateCalls)
|
||||||
reqTun := testutil.RequireRecvCtx(ctx, t, call.Reqs)
|
reqTun := testutil.RequireRecvCtx(ctx, t, call.Reqs)
|
||||||
@ -127,7 +131,8 @@ func TestTailnetAPIConnector_UplevelVersion(t *testing.T) {
|
|||||||
|
|
||||||
fConn := newFakeTailnetConn()
|
fConn := newFakeTailnetConn()
|
||||||
|
|
||||||
uut := runTailnetAPIConnector(ctx, logger, agentID, svr.URL, &websocket.DialOptions{}, fConn)
|
uut := newTailnetAPIConnector(ctx, logger, agentID, svr.URL, &websocket.DialOptions{})
|
||||||
|
uut.runConnector(fConn)
|
||||||
|
|
||||||
err := testutil.RequireRecvCtx(ctx, t, uut.connected)
|
err := testutil.RequireRecvCtx(ctx, t, uut.connected)
|
||||||
var sdkErr *codersdk.Error
|
var sdkErr *codersdk.Error
|
||||||
@ -137,6 +142,144 @@ func TestTailnetAPIConnector_UplevelVersion(t *testing.T) {
|
|||||||
require.NotEmpty(t, sdkErr.Helper)
|
require.NotEmpty(t, sdkErr.Helper)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTailnetAPIConnector_TelemetrySuccess(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
ctx := testutil.Context(t, testutil.WaitShort)
|
||||||
|
logger := slogtest.Make(t, nil).Leveled(slog.LevelDebug)
|
||||||
|
agentID := uuid.UUID{0x55}
|
||||||
|
clientID := uuid.UUID{0x66}
|
||||||
|
fCoord := tailnettest.NewFakeCoordinator()
|
||||||
|
var coord tailnet.Coordinator = fCoord
|
||||||
|
coordPtr := atomic.Pointer[tailnet.Coordinator]{}
|
||||||
|
coordPtr.Store(&coord)
|
||||||
|
derpMapCh := make(chan *tailcfg.DERPMap)
|
||||||
|
defer close(derpMapCh)
|
||||||
|
eventCh := make(chan []*proto.TelemetryEvent, 1)
|
||||||
|
svc, err := tailnet.NewClientService(tailnet.ClientServiceOptions{
|
||||||
|
Logger: logger,
|
||||||
|
CoordPtr: &coordPtr,
|
||||||
|
DERPMapUpdateFrequency: time.Millisecond,
|
||||||
|
DERPMapFn: func() *tailcfg.DERPMap { return <-derpMapCh },
|
||||||
|
NetworkTelemetryHandler: func(batch []*proto.TelemetryEvent) {
|
||||||
|
eventCh <- batch
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
sws, err := websocket.Accept(w, r, nil)
|
||||||
|
if !assert.NoError(t, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx, nc := codersdk.WebsocketNetConn(r.Context(), sws, websocket.MessageBinary)
|
||||||
|
err = svc.ServeConnV2(ctx, nc, tailnet.StreamID{
|
||||||
|
Name: "client",
|
||||||
|
ID: clientID,
|
||||||
|
Auth: tailnet.ClientCoordinateeAuth{AgentID: agentID},
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}))
|
||||||
|
|
||||||
|
fConn := newFakeTailnetConn()
|
||||||
|
|
||||||
|
uut := newTailnetAPIConnector(ctx, logger, agentID, svr.URL, &websocket.DialOptions{})
|
||||||
|
uut.runConnector(fConn)
|
||||||
|
require.Eventually(t, func() bool {
|
||||||
|
uut.clientMu.Lock()
|
||||||
|
defer uut.clientMu.Unlock()
|
||||||
|
return uut.client != nil
|
||||||
|
}, testutil.WaitShort, testutil.IntervalFast)
|
||||||
|
|
||||||
|
uut.SendTelemetryEvent(&proto.TelemetryEvent{
|
||||||
|
Id: []byte("test event"),
|
||||||
|
})
|
||||||
|
|
||||||
|
testEvents := testutil.RequireRecvCtx(ctx, t, eventCh)
|
||||||
|
|
||||||
|
require.Len(t, testEvents, 1)
|
||||||
|
require.Equal(t, []byte("test event"), testEvents[0].Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTailnetAPIConnector_TelemetryUnimplemented(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
ctx := testutil.Context(t, testutil.WaitShort)
|
||||||
|
logger := slogtest.Make(t, nil).Leveled(slog.LevelDebug)
|
||||||
|
agentID := uuid.UUID{0x55}
|
||||||
|
fConn := newFakeTailnetConn()
|
||||||
|
|
||||||
|
fakeDRPCClient := newFakeDRPCClient()
|
||||||
|
uut := &tailnetAPIConnector{
|
||||||
|
ctx: ctx,
|
||||||
|
logger: logger,
|
||||||
|
agentID: agentID,
|
||||||
|
coordinateURL: "",
|
||||||
|
dialOptions: &websocket.DialOptions{},
|
||||||
|
conn: nil,
|
||||||
|
connected: make(chan error, 1),
|
||||||
|
closed: make(chan struct{}),
|
||||||
|
customDialFn: func() (proto.DRPCTailnetClient, error) {
|
||||||
|
return fakeDRPCClient, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
uut.runConnector(fConn)
|
||||||
|
require.Eventually(t, func() bool {
|
||||||
|
uut.clientMu.Lock()
|
||||||
|
defer uut.clientMu.Unlock()
|
||||||
|
return uut.client != nil
|
||||||
|
}, testutil.WaitShort, testutil.IntervalFast)
|
||||||
|
|
||||||
|
fakeDRPCClient.telemeteryErorr = drpcerr.WithCode(xerrors.New("Unimplemented"), 0)
|
||||||
|
uut.SendTelemetryEvent(&proto.TelemetryEvent{})
|
||||||
|
require.False(t, uut.telemetryUnavailable.Load())
|
||||||
|
require.Equal(t, int64(1), atomic.LoadInt64(&fakeDRPCClient.postTelemetryCalls))
|
||||||
|
|
||||||
|
fakeDRPCClient.telemeteryErorr = drpcerr.WithCode(xerrors.New("Unimplemented"), drpcerr.Unimplemented)
|
||||||
|
uut.SendTelemetryEvent(&proto.TelemetryEvent{})
|
||||||
|
require.True(t, uut.telemetryUnavailable.Load())
|
||||||
|
uut.SendTelemetryEvent(&proto.TelemetryEvent{})
|
||||||
|
require.Equal(t, int64(2), atomic.LoadInt64(&fakeDRPCClient.postTelemetryCalls))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTailnetAPIConnector_TelemetryNotRecognised(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
ctx := testutil.Context(t, testutil.WaitShort)
|
||||||
|
logger := slogtest.Make(t, nil).Leveled(slog.LevelDebug)
|
||||||
|
agentID := uuid.UUID{0x55}
|
||||||
|
fConn := newFakeTailnetConn()
|
||||||
|
|
||||||
|
fakeDRPCClient := newFakeDRPCClient()
|
||||||
|
uut := &tailnetAPIConnector{
|
||||||
|
ctx: ctx,
|
||||||
|
logger: logger,
|
||||||
|
agentID: agentID,
|
||||||
|
coordinateURL: "",
|
||||||
|
dialOptions: &websocket.DialOptions{},
|
||||||
|
conn: nil,
|
||||||
|
connected: make(chan error, 1),
|
||||||
|
closed: make(chan struct{}),
|
||||||
|
customDialFn: func() (proto.DRPCTailnetClient, error) {
|
||||||
|
return fakeDRPCClient, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
uut.runConnector(fConn)
|
||||||
|
require.Eventually(t, func() bool {
|
||||||
|
uut.clientMu.Lock()
|
||||||
|
defer uut.clientMu.Unlock()
|
||||||
|
return uut.client != nil
|
||||||
|
}, testutil.WaitShort, testutil.IntervalFast)
|
||||||
|
|
||||||
|
fakeDRPCClient.telemeteryErorr = drpc.ProtocolError.New("Protocol Error")
|
||||||
|
uut.SendTelemetryEvent(&proto.TelemetryEvent{})
|
||||||
|
require.False(t, uut.telemetryUnavailable.Load())
|
||||||
|
require.Equal(t, int64(1), atomic.LoadInt64(&fakeDRPCClient.postTelemetryCalls))
|
||||||
|
|
||||||
|
fakeDRPCClient.telemeteryErorr = drpc.ProtocolError.New("unknown rpc: /coder.tailnet.v2.Tailnet/PostTelemetry")
|
||||||
|
uut.SendTelemetryEvent(&proto.TelemetryEvent{})
|
||||||
|
require.True(t, uut.telemetryUnavailable.Load())
|
||||||
|
uut.SendTelemetryEvent(&proto.TelemetryEvent{})
|
||||||
|
require.Equal(t, int64(2), atomic.LoadInt64(&fakeDRPCClient.postTelemetryCalls))
|
||||||
|
}
|
||||||
|
|
||||||
type fakeTailnetConn struct{}
|
type fakeTailnetConn struct{}
|
||||||
|
|
||||||
func (*fakeTailnetConn) UpdatePeers([]*proto.CoordinateResponse_PeerUpdate) error {
|
func (*fakeTailnetConn) UpdatePeers([]*proto.CoordinateResponse_PeerUpdate) error {
|
||||||
@ -155,3 +298,123 @@ func (*fakeTailnetConn) SetTunnelDestination(uuid.UUID) {}
|
|||||||
func newFakeTailnetConn() *fakeTailnetConn {
|
func newFakeTailnetConn() *fakeTailnetConn {
|
||||||
return &fakeTailnetConn{}
|
return &fakeTailnetConn{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fakeDRPCClient struct {
|
||||||
|
postTelemetryCalls int64
|
||||||
|
telemeteryErorr error
|
||||||
|
fakeDRPPCMapStream
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ proto.DRPCTailnetClient = &fakeDRPCClient{}
|
||||||
|
|
||||||
|
func newFakeDRPCClient() *fakeDRPCClient {
|
||||||
|
return &fakeDRPCClient{
|
||||||
|
postTelemetryCalls: 0,
|
||||||
|
fakeDRPPCMapStream: fakeDRPPCMapStream{
|
||||||
|
fakeDRPCStream: fakeDRPCStream{
|
||||||
|
ch: make(chan struct{}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Coordinate implements proto.DRPCTailnetClient.
|
||||||
|
func (f *fakeDRPCClient) Coordinate(_ context.Context) (proto.DRPCTailnet_CoordinateClient, error) {
|
||||||
|
return &f.fakeDRPCStream, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DRPCConn implements proto.DRPCTailnetClient.
|
||||||
|
func (*fakeDRPCClient) DRPCConn() drpc.Conn {
|
||||||
|
return &fakeDRPCConn{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostTelemetry implements proto.DRPCTailnetClient.
|
||||||
|
func (f *fakeDRPCClient) PostTelemetry(_ context.Context, _ *proto.TelemetryRequest) (*proto.TelemetryResponse, error) {
|
||||||
|
atomic.AddInt64(&f.postTelemetryCalls, 1)
|
||||||
|
return nil, f.telemeteryErorr
|
||||||
|
}
|
||||||
|
|
||||||
|
// StreamDERPMaps implements proto.DRPCTailnetClient.
|
||||||
|
func (f *fakeDRPCClient) StreamDERPMaps(_ context.Context, _ *proto.StreamDERPMapsRequest) (proto.DRPCTailnet_StreamDERPMapsClient, error) {
|
||||||
|
return &f.fakeDRPPCMapStream, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type fakeDRPCConn struct{}
|
||||||
|
|
||||||
|
var _ drpc.Conn = &fakeDRPCConn{}
|
||||||
|
|
||||||
|
// Close implements drpc.Conn.
|
||||||
|
func (*fakeDRPCConn) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closed implements drpc.Conn.
|
||||||
|
func (*fakeDRPCConn) Closed() <-chan struct{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoke implements drpc.Conn.
|
||||||
|
func (*fakeDRPCConn) Invoke(_ context.Context, _ string, _ drpc.Encoding, _ drpc.Message, _ drpc.Message) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStream implements drpc.Conn.
|
||||||
|
func (*fakeDRPCConn) NewStream(_ context.Context, _ string, _ drpc.Encoding) (drpc.Stream, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type fakeDRPCStream struct {
|
||||||
|
ch chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ proto.DRPCTailnet_CoordinateClient = &fakeDRPCStream{}
|
||||||
|
|
||||||
|
// Close implements proto.DRPCTailnet_CoordinateClient.
|
||||||
|
func (f *fakeDRPCStream) Close() error {
|
||||||
|
close(f.ch)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseSend implements proto.DRPCTailnet_CoordinateClient.
|
||||||
|
func (*fakeDRPCStream) CloseSend() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context implements proto.DRPCTailnet_CoordinateClient.
|
||||||
|
func (*fakeDRPCStream) Context() context.Context {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MsgRecv implements proto.DRPCTailnet_CoordinateClient.
|
||||||
|
func (*fakeDRPCStream) MsgRecv(_ drpc.Message, _ drpc.Encoding) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MsgSend implements proto.DRPCTailnet_CoordinateClient.
|
||||||
|
func (*fakeDRPCStream) MsgSend(_ drpc.Message, _ drpc.Encoding) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recv implements proto.DRPCTailnet_CoordinateClient.
|
||||||
|
func (f *fakeDRPCStream) Recv() (*proto.CoordinateResponse, error) {
|
||||||
|
<-f.ch
|
||||||
|
return &proto.CoordinateResponse{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send implements proto.DRPCTailnet_CoordinateClient.
|
||||||
|
func (f *fakeDRPCStream) Send(*proto.CoordinateRequest) error {
|
||||||
|
<-f.ch
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type fakeDRPPCMapStream struct {
|
||||||
|
fakeDRPCStream
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ proto.DRPCTailnet_StreamDERPMapsClient = &fakeDRPPCMapStream{}
|
||||||
|
|
||||||
|
// Recv implements proto.DRPCTailnet_StreamDERPMapsClient.
|
||||||
|
func (f *fakeDRPPCMapStream) Recv() (*proto.DERPMap, error) {
|
||||||
|
<-f.fakeDRPCStream.ch
|
||||||
|
return &proto.DERPMap{}, nil
|
||||||
|
}
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"cdr.dev/slog"
|
"cdr.dev/slog"
|
||||||
"github.com/coder/coder/v2/codersdk"
|
"github.com/coder/coder/v2/codersdk"
|
||||||
"github.com/coder/coder/v2/tailnet"
|
"github.com/coder/coder/v2/tailnet"
|
||||||
|
"github.com/coder/coder/v2/tailnet/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AgentIP is a static IPv6 address with the Tailscale prefix that is used to route
|
// AgentIP is a static IPv6 address with the Tailscale prefix that is used to route
|
||||||
@ -181,6 +182,9 @@ type DialAgentOptions struct {
|
|||||||
// CaptureHook is a callback that captures Disco packets and packets sent
|
// CaptureHook is a callback that captures Disco packets and packets sent
|
||||||
// into the tailnet tunnel.
|
// into the tailnet tunnel.
|
||||||
CaptureHook capture.Callback
|
CaptureHook capture.Callback
|
||||||
|
// Whether the client will send network telemetry events.
|
||||||
|
// Enable instead of Disable so it's initialized to false (in tests).
|
||||||
|
EnableTelemetry bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) DialAgent(dialCtx context.Context, agentID uuid.UUID, options *DialAgentOptions) (agentConn *AgentConn, err error) {
|
func (c *Client) DialAgent(dialCtx context.Context, agentID uuid.UUID, options *DialAgentOptions) (agentConn *AgentConn, err error) {
|
||||||
@ -196,29 +200,6 @@ func (c *Client) DialAgent(dialCtx context.Context, agentID uuid.UUID, options *
|
|||||||
options.BlockEndpoints = true
|
options.BlockEndpoints = true
|
||||||
}
|
}
|
||||||
|
|
||||||
ip := tailnet.IP()
|
|
||||||
var header http.Header
|
|
||||||
if headerTransport, ok := c.client.HTTPClient.Transport.(*codersdk.HeaderTransport); ok {
|
|
||||||
header = headerTransport.Header
|
|
||||||
}
|
|
||||||
conn, err := tailnet.NewConn(&tailnet.Options{
|
|
||||||
Addresses: []netip.Prefix{netip.PrefixFrom(ip, 128)},
|
|
||||||
DERPMap: connInfo.DERPMap,
|
|
||||||
DERPHeader: &header,
|
|
||||||
DERPForceWebSockets: connInfo.DERPForceWebSockets,
|
|
||||||
Logger: options.Logger,
|
|
||||||
BlockEndpoints: c.client.DisableDirectConnections || options.BlockEndpoints,
|
|
||||||
CaptureHook: options.CaptureHook,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("create tailnet: %w", err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
_ = conn.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
headers := make(http.Header)
|
headers := make(http.Header)
|
||||||
tokenHeader := codersdk.SessionTokenHeader
|
tokenHeader := codersdk.SessionTokenHeader
|
||||||
if c.client.SessionTokenHeader != "" {
|
if c.client.SessionTokenHeader != "" {
|
||||||
@ -251,16 +232,44 @@ func (c *Client) DialAgent(dialCtx context.Context, agentID uuid.UUID, options *
|
|||||||
q.Add("version", "2.0")
|
q.Add("version", "2.0")
|
||||||
coordinateURL.RawQuery = q.Encode()
|
coordinateURL.RawQuery = q.Encode()
|
||||||
|
|
||||||
connector := runTailnetAPIConnector(ctx, options.Logger,
|
connector := newTailnetAPIConnector(ctx, options.Logger, agentID, coordinateURL.String(),
|
||||||
agentID, coordinateURL.String(),
|
|
||||||
&websocket.DialOptions{
|
&websocket.DialOptions{
|
||||||
HTTPClient: c.client.HTTPClient,
|
HTTPClient: c.client.HTTPClient,
|
||||||
HTTPHeader: headers,
|
HTTPHeader: headers,
|
||||||
// Need to disable compression to avoid a data-race.
|
// Need to disable compression to avoid a data-race.
|
||||||
CompressionMode: websocket.CompressionDisabled,
|
CompressionMode: websocket.CompressionDisabled,
|
||||||
},
|
})
|
||||||
conn,
|
|
||||||
)
|
ip := tailnet.IP()
|
||||||
|
var header http.Header
|
||||||
|
if headerTransport, ok := c.client.HTTPClient.Transport.(*codersdk.HeaderTransport); ok {
|
||||||
|
header = headerTransport.Header
|
||||||
|
}
|
||||||
|
var telemetrySink tailnet.TelemetrySink
|
||||||
|
if options.EnableTelemetry {
|
||||||
|
telemetrySink = connector
|
||||||
|
}
|
||||||
|
conn, err := tailnet.NewConn(&tailnet.Options{
|
||||||
|
Addresses: []netip.Prefix{netip.PrefixFrom(ip, 128)},
|
||||||
|
DERPMap: connInfo.DERPMap,
|
||||||
|
DERPHeader: &header,
|
||||||
|
DERPForceWebSockets: connInfo.DERPForceWebSockets,
|
||||||
|
Logger: options.Logger,
|
||||||
|
BlockEndpoints: c.client.DisableDirectConnections || options.BlockEndpoints,
|
||||||
|
CaptureHook: options.CaptureHook,
|
||||||
|
ClientType: proto.TelemetryEvent_CLI,
|
||||||
|
TelemetrySink: telemetrySink,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("create tailnet: %w", err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
_ = conn.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
connector.runConnector(conn)
|
||||||
|
|
||||||
options.Logger.Debug(ctx, "running tailnet API v2+ connector")
|
options.Logger.Debug(ctx, "running tailnet API v2+ connector")
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
12
docs/cli.md
12
docs/cli.md
@ -149,6 +149,18 @@ Enable verbose output.
|
|||||||
|
|
||||||
Disable direct (P2P) connections to workspaces.
|
Disable direct (P2P) connections to workspaces.
|
||||||
|
|
||||||
|
### --disable-network-telemetry
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ----------- | --------------------------------------------- |
|
||||||
|
| Type | <code>bool</code> |
|
||||||
|
| Environment | <code>$CODER_DISABLE_NETWORK_TELEMETRY</code> |
|
||||||
|
|
||||||
|
Disable network telemetry. Network telemetry is collected when connecting to
|
||||||
|
workspaces using the CLI, and is forwarded to the server. If telemetry is also
|
||||||
|
enabled on the server, it may be sent to Coder. Network telemetry is used to
|
||||||
|
measure network quality and detect regressions.
|
||||||
|
|
||||||
### --global-config
|
### --global-config
|
||||||
|
|
||||||
| | |
|
| | |
|
||||||
|
7
enterprise/cli/testdata/coder_--help.golden
vendored
7
enterprise/cli/testdata/coder_--help.golden
vendored
@ -30,6 +30,13 @@ variables or flags.
|
|||||||
--disable-direct-connections bool, $CODER_DISABLE_DIRECT_CONNECTIONS
|
--disable-direct-connections bool, $CODER_DISABLE_DIRECT_CONNECTIONS
|
||||||
Disable direct (P2P) connections to workspaces.
|
Disable direct (P2P) connections to workspaces.
|
||||||
|
|
||||||
|
--disable-network-telemetry bool, $CODER_DISABLE_NETWORK_TELEMETRY
|
||||||
|
Disable network telemetry. Network telemetry is collected when
|
||||||
|
connecting to workspaces using the CLI, and is forwarded to the
|
||||||
|
server. If telemetry is also enabled on the server, it may be sent to
|
||||||
|
Coder. Network telemetry is used to measure network quality and detect
|
||||||
|
regressions.
|
||||||
|
|
||||||
--global-config string, $CODER_CONFIG_DIR (default: ~/.config/coderv2)
|
--global-config string, $CODER_CONFIG_DIR (default: ~/.config/coderv2)
|
||||||
Path to the global `coder` config directory.
|
Path to the global `coder` config directory.
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@
|
|||||||
name = "coder-${osArch}";
|
name = "coder-${osArch}";
|
||||||
# Updated with ./scripts/update-flake.sh`.
|
# Updated with ./scripts/update-flake.sh`.
|
||||||
# This should be updated whenever go.mod changes!
|
# This should be updated whenever go.mod changes!
|
||||||
vendorHash = "sha256-e0L6osJwG0EF0M3TefxaAjDvN4jvQHxTGEUEECNO1Vw=";
|
vendorHash = "sha256-5R2FelgM9NRYlse309NukEVh25pvusO2FXZx1VuWGoo=";
|
||||||
proxyVendor = true;
|
proxyVendor = true;
|
||||||
src = ./.;
|
src = ./.;
|
||||||
nativeBuildInputs = with pkgs; [ getopt openssl zstd ];
|
nativeBuildInputs = with pkgs; [ getopt openssl zstd ];
|
||||||
|
2
go.mod
2
go.mod
@ -42,7 +42,7 @@ replace github.com/dlclark/regexp2 => github.com/dlclark/regexp2 v1.7.0
|
|||||||
|
|
||||||
// There are a few minor changes we make to Tailscale that we're slowly upstreaming. Compare here:
|
// There are a few minor changes we make to Tailscale that we're slowly upstreaming. Compare here:
|
||||||
// https://github.com/tailscale/tailscale/compare/main...coder:tailscale:main
|
// https://github.com/tailscale/tailscale/compare/main...coder:tailscale:main
|
||||||
replace tailscale.com => github.com/coder/tailscale v1.1.1-0.20240530071520-1ac63d3a4ee3
|
replace tailscale.com => github.com/coder/tailscale v1.1.1-0.20240702054557-aa558fbe5374
|
||||||
|
|
||||||
// This is replaced to include
|
// This is replaced to include
|
||||||
// 1. a fix for a data race: c.f. https://github.com/tailscale/wireguard-go/pull/25
|
// 1. a fix for a data race: c.f. https://github.com/tailscale/wireguard-go/pull/25
|
||||||
|
4
go.sum
4
go.sum
@ -213,8 +213,8 @@ github.com/coder/serpent v0.7.0 h1:zGpD2GlF3lKIVkMjNGKbkip88qzd5r/TRcc30X/SrT0=
|
|||||||
github.com/coder/serpent v0.7.0/go.mod h1:REkJ5ZFHQUWFTPLExhXYZ1CaHFjxvGNRlLXLdsI08YA=
|
github.com/coder/serpent v0.7.0/go.mod h1:REkJ5ZFHQUWFTPLExhXYZ1CaHFjxvGNRlLXLdsI08YA=
|
||||||
github.com/coder/ssh v0.0.0-20231128192721-70855dedb788 h1:YoUSJ19E8AtuUFVYBpXuOD6a/zVP3rcxezNsoDseTUw=
|
github.com/coder/ssh v0.0.0-20231128192721-70855dedb788 h1:YoUSJ19E8AtuUFVYBpXuOD6a/zVP3rcxezNsoDseTUw=
|
||||||
github.com/coder/ssh v0.0.0-20231128192721-70855dedb788/go.mod h1:aGQbuCLyhRLMzZF067xc84Lh7JDs1FKwCmF1Crl9dxQ=
|
github.com/coder/ssh v0.0.0-20231128192721-70855dedb788/go.mod h1:aGQbuCLyhRLMzZF067xc84Lh7JDs1FKwCmF1Crl9dxQ=
|
||||||
github.com/coder/tailscale v1.1.1-0.20240530071520-1ac63d3a4ee3 h1:F2QRxrwPJyMPmX5qU7UpwEenhsk9qDqHyvYFxON1RkI=
|
github.com/coder/tailscale v1.1.1-0.20240702054557-aa558fbe5374 h1:a5Eg7D5e2oAc0tN56ee4yxtiTo76ztpRlk6geljaZp8=
|
||||||
github.com/coder/tailscale v1.1.1-0.20240530071520-1ac63d3a4ee3/go.mod h1:rp6BIJxCp127/hvvDWNkHC9MxAlKvQfoOtBr8s5sCqo=
|
github.com/coder/tailscale v1.1.1-0.20240702054557-aa558fbe5374/go.mod h1:rp6BIJxCp127/hvvDWNkHC9MxAlKvQfoOtBr8s5sCqo=
|
||||||
github.com/coder/terraform-provider-coder v0.23.0 h1:DuNLWxhnGlXyG0g+OCAZRI6xd8+bJjIEnE4F3hYgA4E=
|
github.com/coder/terraform-provider-coder v0.23.0 h1:DuNLWxhnGlXyG0g+OCAZRI6xd8+bJjIEnE4F3hYgA4E=
|
||||||
github.com/coder/terraform-provider-coder v0.23.0/go.mod h1:wMun9UZ9HT2CzF6qPPBup1odzBpVUc0/xSFoXgdI3tk=
|
github.com/coder/terraform-provider-coder v0.23.0/go.mod h1:wMun9UZ9HT2CzF6qPPBup1odzBpVUc0/xSFoXgdI3tk=
|
||||||
github.com/coder/wgtunnel v0.1.13-0.20240522110300-ade90dfb2da0 h1:C2/eCr+r0a5Auuw3YOiSyLNHkdMtyCZHPFBx7syN4rk=
|
github.com/coder/wgtunnel v0.1.13-0.20240522110300-ade90dfb2da0 h1:C2/eCr+r0a5Auuw3YOiSyLNHkdMtyCZHPFBx7syN4rk=
|
||||||
|
@ -283,15 +283,17 @@ func (c *configMaps) getBlockEndpoints() bool {
|
|||||||
|
|
||||||
// setDERPMap sets the DERP map, triggering a configuration of the engine if it has changed.
|
// setDERPMap sets the DERP map, triggering a configuration of the engine if it has changed.
|
||||||
// c.L MUST NOT be held.
|
// c.L MUST NOT be held.
|
||||||
func (c *configMaps) setDERPMap(derpMap *tailcfg.DERPMap) {
|
// Returns if the derpMap is dirty.
|
||||||
|
func (c *configMaps) setDERPMap(derpMap *tailcfg.DERPMap) bool {
|
||||||
c.L.Lock()
|
c.L.Lock()
|
||||||
defer c.L.Unlock()
|
defer c.L.Unlock()
|
||||||
if CompareDERPMaps(c.derpMap, derpMap) {
|
if CompareDERPMaps(c.derpMap, derpMap) {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
c.derpMap = derpMap
|
c.derpMap = derpMap
|
||||||
c.derpMapDirty = true
|
c.derpMapDirty = true
|
||||||
c.Broadcast()
|
c.Broadcast()
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// derMapLocked returns the current DERPMap. c.L must be held
|
// derMapLocked returns the current DERPMap. c.L must be held
|
||||||
|
146
tailnet/conn.go
146
tailnet/conn.go
@ -15,6 +15,8 @@ import (
|
|||||||
"github.com/cenkalti/backoff/v4"
|
"github.com/cenkalti/backoff/v4"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
"google.golang.org/protobuf/types/known/durationpb"
|
||||||
|
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
|
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
|
||||||
"tailscale.com/envknob"
|
"tailscale.com/envknob"
|
||||||
@ -99,6 +101,17 @@ type Options struct {
|
|||||||
// ForceNetworkUp forces the network to be considered up. magicsock will not
|
// ForceNetworkUp forces the network to be considered up. magicsock will not
|
||||||
// do anything if it thinks it can't reach the internet.
|
// do anything if it thinks it can't reach the internet.
|
||||||
ForceNetworkUp bool
|
ForceNetworkUp bool
|
||||||
|
// Network Telemetry Client Type: CLI | Agent | coderd
|
||||||
|
ClientType proto.TelemetryEvent_ClientType
|
||||||
|
// TelemetrySink is optional.
|
||||||
|
TelemetrySink TelemetrySink
|
||||||
|
}
|
||||||
|
|
||||||
|
// TelemetrySink allows tailnet.Conn to send network telemetry to the Coder
|
||||||
|
// server.
|
||||||
|
type TelemetrySink interface {
|
||||||
|
// SendTelemetryEvent sends a telemetry event to some external sink.
|
||||||
|
SendTelemetryEvent(event *proto.TelemetryEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeID creates a Tailscale NodeID from the last 8 bytes of a UUID. It ensures
|
// NodeID creates a Tailscale NodeID from the last 8 bytes of a UUID. It ensures
|
||||||
@ -122,6 +135,15 @@ func NewConn(options *Options) (conn *Conn, err error) {
|
|||||||
return nil, xerrors.New("At least one IP range must be provided")
|
return nil, xerrors.New("At least one IP range must be provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var telemetryStore *TelemetryStore
|
||||||
|
if options.TelemetrySink != nil {
|
||||||
|
var err error
|
||||||
|
telemetryStore, err = newTelemetryStore()
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("create telemetry store: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nodePrivateKey := key.NewNode()
|
nodePrivateKey := key.NewNode()
|
||||||
var nodeID tailcfg.NodeID
|
var nodeID tailcfg.NodeID
|
||||||
|
|
||||||
@ -241,10 +263,18 @@ func NewConn(options *Options) (conn *Conn, err error) {
|
|||||||
nodeUp.setAddresses(options.Addresses)
|
nodeUp.setAddresses(options.Addresses)
|
||||||
nodeUp.setBlockEndpoints(options.BlockEndpoints)
|
nodeUp.setBlockEndpoints(options.BlockEndpoints)
|
||||||
wireguardEngine.SetStatusCallback(nodeUp.setStatus)
|
wireguardEngine.SetStatusCallback(nodeUp.setStatus)
|
||||||
wireguardEngine.SetNetInfoCallback(nodeUp.setNetInfo)
|
|
||||||
magicConn.SetDERPForcedWebsocketCallback(nodeUp.setDERPForcedWebsocket)
|
magicConn.SetDERPForcedWebsocketCallback(nodeUp.setDERPForcedWebsocket)
|
||||||
|
if telemetryStore != nil {
|
||||||
|
wireguardEngine.SetNetInfoCallback(func(ni *tailcfg.NetInfo) {
|
||||||
|
nodeUp.setNetInfo(ni)
|
||||||
|
telemetryStore.setNetInfo(ni)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
wireguardEngine.SetNetInfoCallback(nodeUp.setNetInfo)
|
||||||
|
}
|
||||||
|
|
||||||
server := &Conn{
|
server := &Conn{
|
||||||
|
id: uuid.New(),
|
||||||
closed: make(chan struct{}),
|
closed: make(chan struct{}),
|
||||||
logger: options.Logger,
|
logger: options.Logger,
|
||||||
magicConn: magicConn,
|
magicConn: magicConn,
|
||||||
@ -259,6 +289,8 @@ func NewConn(options *Options) (conn *Conn, err error) {
|
|||||||
wireguardEngine: wireguardEngine,
|
wireguardEngine: wireguardEngine,
|
||||||
configMaps: cfgMaps,
|
configMaps: cfgMaps,
|
||||||
nodeUpdater: nodeUp,
|
nodeUpdater: nodeUp,
|
||||||
|
telemetrySink: options.TelemetrySink,
|
||||||
|
telemeteryStore: telemetryStore,
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -302,6 +334,8 @@ func IPFromUUID(uid uuid.UUID) netip.Addr {
|
|||||||
|
|
||||||
// Conn is an actively listening Wireguard connection.
|
// Conn is an actively listening Wireguard connection.
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
|
// Unique ID used for telemetry.
|
||||||
|
id uuid.UUID
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
closed chan struct{}
|
closed chan struct{}
|
||||||
logger slog.Logger
|
logger slog.Logger
|
||||||
@ -316,6 +350,12 @@ type Conn struct {
|
|||||||
wireguardRouter *router.Config
|
wireguardRouter *router.Config
|
||||||
wireguardEngine wgengine.Engine
|
wireguardEngine wgengine.Engine
|
||||||
listeners map[listenKey]*listener
|
listeners map[listenKey]*listener
|
||||||
|
clientType proto.TelemetryEvent_ClientType
|
||||||
|
|
||||||
|
telemetrySink TelemetrySink
|
||||||
|
// telemeteryStore will be nil if telemetrySink is nil.
|
||||||
|
telemeteryStore *TelemetryStore
|
||||||
|
telemetryWg sync.WaitGroup
|
||||||
|
|
||||||
trafficStats *connstats.Statistics
|
trafficStats *connstats.Statistics
|
||||||
}
|
}
|
||||||
@ -350,7 +390,9 @@ func (c *Conn) SetNodeCallback(callback func(node *Node)) {
|
|||||||
|
|
||||||
// SetDERPMap updates the DERPMap of a connection.
|
// SetDERPMap updates the DERPMap of a connection.
|
||||||
func (c *Conn) SetDERPMap(derpMap *tailcfg.DERPMap) {
|
func (c *Conn) SetDERPMap(derpMap *tailcfg.DERPMap) {
|
||||||
c.configMaps.setDERPMap(derpMap)
|
if c.configMaps.setDERPMap(derpMap) && c.telemeteryStore != nil {
|
||||||
|
c.telemeteryStore.updateDerpMap(derpMap)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) SetDERPForceWebSockets(v bool) {
|
func (c *Conn) SetDERPForceWebSockets(v bool) {
|
||||||
@ -399,7 +441,11 @@ func (c *Conn) Status() *ipnstate.Status {
|
|||||||
// Ping sends a ping to the Wireguard engine.
|
// Ping sends a ping to the Wireguard engine.
|
||||||
// The bool returned is true if the ping was performed P2P.
|
// The bool returned is true if the ping was performed P2P.
|
||||||
func (c *Conn) Ping(ctx context.Context, ip netip.Addr) (time.Duration, bool, *ipnstate.PingResult, error) {
|
func (c *Conn) Ping(ctx context.Context, ip netip.Addr) (time.Duration, bool, *ipnstate.PingResult, error) {
|
||||||
return c.pingWithType(ctx, ip, tailcfg.PingDisco)
|
dur, p2p, pr, err := c.pingWithType(ctx, ip, tailcfg.PingDisco)
|
||||||
|
if err == nil {
|
||||||
|
c.sendPingTelemetry(pr)
|
||||||
|
}
|
||||||
|
return dur, p2p, pr, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) pingWithType(ctx context.Context, ip netip.Addr, pt tailcfg.PingType) (time.Duration, bool, *ipnstate.PingResult, error) {
|
func (c *Conn) pingWithType(ctx context.Context, ip netip.Addr, pt tailcfg.PingType) (time.Duration, bool, *ipnstate.PingResult, error) {
|
||||||
@ -494,6 +540,7 @@ func (c *Conn) Closed() <-chan struct{} {
|
|||||||
// Close shuts down the Wireguard connection.
|
// Close shuts down the Wireguard connection.
|
||||||
func (c *Conn) Close() error {
|
func (c *Conn) Close() error {
|
||||||
c.logger.Info(context.Background(), "closing tailnet Conn")
|
c.logger.Info(context.Background(), "closing tailnet Conn")
|
||||||
|
c.telemetryWg.Wait()
|
||||||
c.configMaps.close()
|
c.configMaps.close()
|
||||||
c.nodeUpdater.close()
|
c.nodeUpdater.close()
|
||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
@ -662,6 +709,91 @@ func (c *Conn) MagicsockServeHTTPDebug(w http.ResponseWriter, r *http.Request) {
|
|||||||
c.magicConn.ServeHTTPDebug(w, r)
|
c.magicConn.ServeHTTPDebug(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Conn) SendConnectedTelemetry(ip netip.Addr, application string) {
|
||||||
|
if c.telemetrySink == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e := c.newTelemetryEvent()
|
||||||
|
e.Status = proto.TelemetryEvent_CONNECTED
|
||||||
|
e.Application = application
|
||||||
|
pip, ok := c.wireguardEngine.PeerForIP(ip)
|
||||||
|
if ok {
|
||||||
|
e.NodeIdRemote = uint64(pip.Node.ID)
|
||||||
|
}
|
||||||
|
c.telemetryWg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer c.telemetryWg.Done()
|
||||||
|
c.telemetrySink.SendTelemetryEvent(e)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) SendDisconnectedTelemetry(ip netip.Addr, application string) {
|
||||||
|
if c.telemetrySink == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e := c.newTelemetryEvent()
|
||||||
|
e.Status = proto.TelemetryEvent_DISCONNECTED
|
||||||
|
e.Application = application
|
||||||
|
pip, ok := c.wireguardEngine.PeerForIP(ip)
|
||||||
|
if ok {
|
||||||
|
e.NodeIdRemote = uint64(pip.Node.ID)
|
||||||
|
}
|
||||||
|
c.telemetryWg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer c.telemetryWg.Done()
|
||||||
|
c.telemetrySink.SendTelemetryEvent(e)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) SendSpeedtestTelemetry(throughputMbits float64) {
|
||||||
|
if c.telemetrySink == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e := c.newTelemetryEvent()
|
||||||
|
e.Status = proto.TelemetryEvent_CONNECTED
|
||||||
|
e.ThroughputMbits = wrapperspb.Float(float32(throughputMbits))
|
||||||
|
c.telemetryWg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer c.telemetryWg.Done()
|
||||||
|
c.telemetrySink.SendTelemetryEvent(e)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint:revive
|
||||||
|
func (c *Conn) sendPingTelemetry(pr *ipnstate.PingResult) {
|
||||||
|
if c.telemetrySink == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e := c.newTelemetryEvent()
|
||||||
|
|
||||||
|
latency := durationpb.New(time.Duration(pr.LatencySeconds * float64(time.Second)))
|
||||||
|
if pr.Endpoint != "" {
|
||||||
|
e.P2PLatency = latency
|
||||||
|
e.P2PEndpoint = c.telemeteryStore.toEndpoint(pr.Endpoint)
|
||||||
|
} else {
|
||||||
|
e.DerpLatency = latency
|
||||||
|
}
|
||||||
|
e.Status = proto.TelemetryEvent_CONNECTED
|
||||||
|
c.telemetryWg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer c.telemetryWg.Done()
|
||||||
|
c.telemetrySink.SendTelemetryEvent(e)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// The returned telemetry event will not have it's status set.
|
||||||
|
func (c *Conn) newTelemetryEvent() *proto.TelemetryEvent {
|
||||||
|
// Infallible
|
||||||
|
id, _ := c.id.MarshalBinary()
|
||||||
|
event := c.telemeteryStore.newEvent()
|
||||||
|
event.ClientType = c.clientType
|
||||||
|
event.Id = id
|
||||||
|
selfNode := c.Node()
|
||||||
|
event.NodeIdSelf = uint64(selfNode.ID)
|
||||||
|
event.HomeDerp = strconv.Itoa(selfNode.PreferredDERP)
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
// PeerDiagnostics is a checklist of human-readable conditions necessary to establish an encrypted
|
// PeerDiagnostics is a checklist of human-readable conditions necessary to establish an encrypted
|
||||||
// tunnel to a peer via a Conn
|
// tunnel to a peer via a Conn
|
||||||
type PeerDiagnostics struct {
|
type PeerDiagnostics struct {
|
||||||
@ -730,8 +862,12 @@ type addr struct{ ln *listener }
|
|||||||
func (a addr) Network() string { return a.ln.key.network }
|
func (a addr) Network() string { return a.ln.key.network }
|
||||||
func (a addr) String() string { return a.ln.addr }
|
func (a addr) String() string { return a.ln.addr }
|
||||||
|
|
||||||
// Logger converts the Tailscale logging function to use slog.
|
// Logger converts the Tailscale logging function to use a slog-compatible
|
||||||
func Logger(logger slog.Logger) tslogger.Logf {
|
// logger.
|
||||||
|
func Logger(logger interface {
|
||||||
|
Debug(ctx context.Context, str string, args ...any)
|
||||||
|
},
|
||||||
|
) tslogger.Logf {
|
||||||
return tslogger.Logf(func(format string, args ...any) {
|
return tslogger.Logf(func(format string, args ...any) {
|
||||||
slog.Helper()
|
slog.Helper()
|
||||||
logger.Debug(context.Background(), fmt.Sprintf(format, args...))
|
logger.Debug(context.Background(), fmt.Sprintf(format, args...))
|
||||||
|
@ -81,11 +81,10 @@ func (CoordinateResponse_PeerUpdate_Kind) EnumDescriptor() ([]byte, []int) {
|
|||||||
type IPFields_IPClass int32
|
type IPFields_IPClass int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
IPFields_PUBLIC IPFields_IPClass = 0
|
IPFields_PUBLIC IPFields_IPClass = 0
|
||||||
IPFields_PRIVATE IPFields_IPClass = 1
|
IPFields_PRIVATE IPFields_IPClass = 1
|
||||||
IPFields_LINK_LOCAL IPFields_IPClass = 2
|
IPFields_LINK_LOCAL IPFields_IPClass = 2
|
||||||
IPFields_UNIQUE_LOCAL IPFields_IPClass = 3
|
IPFields_LOOPBACK IPFields_IPClass = 3
|
||||||
IPFields_LOOPBACK IPFields_IPClass = 4
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Enum value maps for IPFields_IPClass.
|
// Enum value maps for IPFields_IPClass.
|
||||||
@ -94,15 +93,13 @@ var (
|
|||||||
0: "PUBLIC",
|
0: "PUBLIC",
|
||||||
1: "PRIVATE",
|
1: "PRIVATE",
|
||||||
2: "LINK_LOCAL",
|
2: "LINK_LOCAL",
|
||||||
3: "UNIQUE_LOCAL",
|
3: "LOOPBACK",
|
||||||
4: "LOOPBACK",
|
|
||||||
}
|
}
|
||||||
IPFields_IPClass_value = map[string]int32{
|
IPFields_IPClass_value = map[string]int32{
|
||||||
"PUBLIC": 0,
|
"PUBLIC": 0,
|
||||||
"PRIVATE": 1,
|
"PRIVATE": 1,
|
||||||
"LINK_LOCAL": 2,
|
"LINK_LOCAL": 2,
|
||||||
"UNIQUE_LOCAL": 3,
|
"LOOPBACK": 3,
|
||||||
"LOOPBACK": 4,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -643,20 +640,18 @@ type Netcheck struct {
|
|||||||
IPv4 bool `protobuf:"varint,3,opt,name=IPv4,proto3" json:"IPv4,omitempty"`
|
IPv4 bool `protobuf:"varint,3,opt,name=IPv4,proto3" json:"IPv4,omitempty"`
|
||||||
IPv6CanSend bool `protobuf:"varint,4,opt,name=IPv6CanSend,proto3" json:"IPv6CanSend,omitempty"`
|
IPv6CanSend bool `protobuf:"varint,4,opt,name=IPv6CanSend,proto3" json:"IPv6CanSend,omitempty"`
|
||||||
IPv4CanSend bool `protobuf:"varint,5,opt,name=IPv4CanSend,proto3" json:"IPv4CanSend,omitempty"`
|
IPv4CanSend bool `protobuf:"varint,5,opt,name=IPv4CanSend,proto3" json:"IPv4CanSend,omitempty"`
|
||||||
OSHasIPv6 bool `protobuf:"varint,6,opt,name=OSHasIPv6,proto3" json:"OSHasIPv6,omitempty"`
|
ICMPv4 bool `protobuf:"varint,6,opt,name=ICMPv4,proto3" json:"ICMPv4,omitempty"`
|
||||||
ICMPv4 bool `protobuf:"varint,7,opt,name=ICMPv4,proto3" json:"ICMPv4,omitempty"`
|
OSHasIPv6 *wrapperspb.BoolValue `protobuf:"bytes,7,opt,name=OSHasIPv6,proto3" json:"OSHasIPv6,omitempty"`
|
||||||
MappingVariesByDestIP *wrapperspb.BoolValue `protobuf:"bytes,8,opt,name=MappingVariesByDestIP,proto3" json:"MappingVariesByDestIP,omitempty"`
|
MappingVariesByDestIP *wrapperspb.BoolValue `protobuf:"bytes,8,opt,name=MappingVariesByDestIP,proto3" json:"MappingVariesByDestIP,omitempty"`
|
||||||
HairPinning *wrapperspb.BoolValue `protobuf:"bytes,9,opt,name=HairPinning,proto3" json:"HairPinning,omitempty"`
|
HairPinning *wrapperspb.BoolValue `protobuf:"bytes,9,opt,name=HairPinning,proto3" json:"HairPinning,omitempty"`
|
||||||
UPnP *wrapperspb.BoolValue `protobuf:"bytes,10,opt,name=UPnP,proto3" json:"UPnP,omitempty"`
|
UPnP *wrapperspb.BoolValue `protobuf:"bytes,10,opt,name=UPnP,proto3" json:"UPnP,omitempty"`
|
||||||
PMP *wrapperspb.BoolValue `protobuf:"bytes,11,opt,name=PMP,proto3" json:"PMP,omitempty"`
|
PMP *wrapperspb.BoolValue `protobuf:"bytes,11,opt,name=PMP,proto3" json:"PMP,omitempty"`
|
||||||
PCP *wrapperspb.BoolValue `protobuf:"bytes,12,opt,name=PCP,proto3" json:"PCP,omitempty"`
|
PCP *wrapperspb.BoolValue `protobuf:"bytes,12,opt,name=PCP,proto3" json:"PCP,omitempty"`
|
||||||
PreferredDERP int64 `protobuf:"varint,13,opt,name=PreferredDERP,proto3" json:"PreferredDERP,omitempty"` // 0 for unknown
|
PreferredDERP int64 `protobuf:"varint,13,opt,name=PreferredDERP,proto3" json:"PreferredDERP,omitempty"` // 0 for unknown
|
||||||
RegionLatency map[int64]*durationpb.Duration `protobuf:"bytes,14,rep,name=RegionLatency,proto3" json:"RegionLatency,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
RegionV4Latency map[int64]*durationpb.Duration `protobuf:"bytes,14,rep,name=RegionV4Latency,proto3" json:"RegionV4Latency,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
RegionV4Latency map[int64]*durationpb.Duration `protobuf:"bytes,15,rep,name=RegionV4Latency,proto3" json:"RegionV4Latency,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
RegionV6Latency map[int64]*durationpb.Duration `protobuf:"bytes,15,rep,name=RegionV6Latency,proto3" json:"RegionV6Latency,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
RegionV6Latency map[int64]*durationpb.Duration `protobuf:"bytes,16,rep,name=RegionV6Latency,proto3" json:"RegionV6Latency,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
|
||||||
GlobalV4 *Netcheck_NetcheckIP `protobuf:"bytes,17,opt,name=GlobalV4,proto3" json:"GlobalV4,omitempty"`
|
GlobalV4 *Netcheck_NetcheckIP `protobuf:"bytes,17,opt,name=GlobalV4,proto3" json:"GlobalV4,omitempty"`
|
||||||
GlobalV6 *Netcheck_NetcheckIP `protobuf:"bytes,18,opt,name=GlobalV6,proto3" json:"GlobalV6,omitempty"`
|
GlobalV6 *Netcheck_NetcheckIP `protobuf:"bytes,18,opt,name=GlobalV6,proto3" json:"GlobalV6,omitempty"`
|
||||||
CaptivePortal *wrapperspb.BoolValue `protobuf:"bytes,19,opt,name=CaptivePortal,proto3" json:"CaptivePortal,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Netcheck) Reset() {
|
func (x *Netcheck) Reset() {
|
||||||
@ -726,13 +721,6 @@ func (x *Netcheck) GetIPv4CanSend() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Netcheck) GetOSHasIPv6() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.OSHasIPv6
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Netcheck) GetICMPv4() bool {
|
func (x *Netcheck) GetICMPv4() bool {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.ICMPv4
|
return x.ICMPv4
|
||||||
@ -740,6 +728,13 @@ func (x *Netcheck) GetICMPv4() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Netcheck) GetOSHasIPv6() *wrapperspb.BoolValue {
|
||||||
|
if x != nil {
|
||||||
|
return x.OSHasIPv6
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (x *Netcheck) GetMappingVariesByDestIP() *wrapperspb.BoolValue {
|
func (x *Netcheck) GetMappingVariesByDestIP() *wrapperspb.BoolValue {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.MappingVariesByDestIP
|
return x.MappingVariesByDestIP
|
||||||
@ -782,13 +777,6 @@ func (x *Netcheck) GetPreferredDERP() int64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Netcheck) GetRegionLatency() map[int64]*durationpb.Duration {
|
|
||||||
if x != nil {
|
|
||||||
return x.RegionLatency
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Netcheck) GetRegionV4Latency() map[int64]*durationpb.Duration {
|
func (x *Netcheck) GetRegionV4Latency() map[int64]*durationpb.Duration {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.RegionV4Latency
|
return x.RegionV4Latency
|
||||||
@ -817,13 +805,6 @@ func (x *Netcheck) GetGlobalV6() *Netcheck_NetcheckIP {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Netcheck) GetCaptivePortal() *wrapperspb.BoolValue {
|
|
||||||
if x != nil {
|
|
||||||
return x.CaptivePortal
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type TelemetryEvent struct {
|
type TelemetryEvent struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@ -838,17 +819,15 @@ type TelemetryEvent struct {
|
|||||||
NodeIdSelf uint64 `protobuf:"varint,7,opt,name=node_id_self,json=nodeIdSelf,proto3" json:"node_id_self,omitempty"`
|
NodeIdSelf uint64 `protobuf:"varint,7,opt,name=node_id_self,json=nodeIdSelf,proto3" json:"node_id_self,omitempty"`
|
||||||
NodeIdRemote uint64 `protobuf:"varint,8,opt,name=node_id_remote,json=nodeIdRemote,proto3" json:"node_id_remote,omitempty"`
|
NodeIdRemote uint64 `protobuf:"varint,8,opt,name=node_id_remote,json=nodeIdRemote,proto3" json:"node_id_remote,omitempty"`
|
||||||
P2PEndpoint *TelemetryEvent_P2PEndpoint `protobuf:"bytes,9,opt,name=p2p_endpoint,json=p2pEndpoint,proto3" json:"p2p_endpoint,omitempty"`
|
P2PEndpoint *TelemetryEvent_P2PEndpoint `protobuf:"bytes,9,opt,name=p2p_endpoint,json=p2pEndpoint,proto3" json:"p2p_endpoint,omitempty"`
|
||||||
LogIpHashes map[string]*IPFields `protobuf:"bytes,10,rep,name=log_ip_hashes,json=logIpHashes,proto3" json:"log_ip_hashes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
HomeDerp string `protobuf:"bytes,10,opt,name=home_derp,json=homeDerp,proto3" json:"home_derp,omitempty"`
|
||||||
HomeDerp string `protobuf:"bytes,11,opt,name=home_derp,json=homeDerp,proto3" json:"home_derp,omitempty"`
|
DerpMap *DERPMap `protobuf:"bytes,11,opt,name=derp_map,json=derpMap,proto3" json:"derp_map,omitempty"`
|
||||||
Logs []string `protobuf:"bytes,12,rep,name=logs,proto3" json:"logs,omitempty"`
|
LatestNetcheck *Netcheck `protobuf:"bytes,12,opt,name=latest_netcheck,json=latestNetcheck,proto3" json:"latest_netcheck,omitempty"`
|
||||||
DerpMap *DERPMap `protobuf:"bytes,13,opt,name=derp_map,json=derpMap,proto3" json:"derp_map,omitempty"`
|
ConnectionAge *durationpb.Duration `protobuf:"bytes,13,opt,name=connection_age,json=connectionAge,proto3" json:"connection_age,omitempty"`
|
||||||
LatestNetcheck *Netcheck `protobuf:"bytes,14,opt,name=latest_netcheck,json=latestNetcheck,proto3" json:"latest_netcheck,omitempty"`
|
ConnectionSetup *durationpb.Duration `protobuf:"bytes,14,opt,name=connection_setup,json=connectionSetup,proto3" json:"connection_setup,omitempty"`
|
||||||
ConnectionAge *durationpb.Duration `protobuf:"bytes,15,opt,name=connection_age,json=connectionAge,proto3" json:"connection_age,omitempty"`
|
P2PSetup *durationpb.Duration `protobuf:"bytes,15,opt,name=p2p_setup,json=p2pSetup,proto3" json:"p2p_setup,omitempty"`
|
||||||
ConnectionSetup *durationpb.Duration `protobuf:"bytes,16,opt,name=connection_setup,json=connectionSetup,proto3" json:"connection_setup,omitempty"`
|
DerpLatency *durationpb.Duration `protobuf:"bytes,16,opt,name=derp_latency,json=derpLatency,proto3" json:"derp_latency,omitempty"`
|
||||||
P2PSetup *durationpb.Duration `protobuf:"bytes,17,opt,name=p2p_setup,json=p2pSetup,proto3" json:"p2p_setup,omitempty"`
|
P2PLatency *durationpb.Duration `protobuf:"bytes,17,opt,name=p2p_latency,json=p2pLatency,proto3" json:"p2p_latency,omitempty"`
|
||||||
DerpLatency *durationpb.Duration `protobuf:"bytes,18,opt,name=derp_latency,json=derpLatency,proto3" json:"derp_latency,omitempty"`
|
ThroughputMbits *wrapperspb.FloatValue `protobuf:"bytes,18,opt,name=throughput_mbits,json=throughputMbits,proto3" json:"throughput_mbits,omitempty"`
|
||||||
P2PLatency *durationpb.Duration `protobuf:"bytes,19,opt,name=p2p_latency,json=p2pLatency,proto3" json:"p2p_latency,omitempty"`
|
|
||||||
ThroughputMbits *wrapperspb.FloatValue `protobuf:"bytes,20,opt,name=throughput_mbits,json=throughputMbits,proto3" json:"throughput_mbits,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *TelemetryEvent) Reset() {
|
func (x *TelemetryEvent) Reset() {
|
||||||
@ -946,13 +925,6 @@ func (x *TelemetryEvent) GetP2PEndpoint() *TelemetryEvent_P2PEndpoint {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *TelemetryEvent) GetLogIpHashes() map[string]*IPFields {
|
|
||||||
if x != nil {
|
|
||||||
return x.LogIpHashes
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *TelemetryEvent) GetHomeDerp() string {
|
func (x *TelemetryEvent) GetHomeDerp() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.HomeDerp
|
return x.HomeDerp
|
||||||
@ -960,13 +932,6 @@ func (x *TelemetryEvent) GetHomeDerp() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *TelemetryEvent) GetLogs() []string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Logs
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *TelemetryEvent) GetDerpMap() *DERPMap {
|
func (x *TelemetryEvent) GetDerpMap() *DERPMap {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.DerpMap
|
return x.DerpMap
|
||||||
@ -1651,7 +1616,7 @@ type Netcheck_NetcheckIP struct {
|
|||||||
func (x *Netcheck_NetcheckIP) Reset() {
|
func (x *Netcheck_NetcheckIP) Reset() {
|
||||||
*x = Netcheck_NetcheckIP{}
|
*x = Netcheck_NetcheckIP{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_tailnet_proto_tailnet_proto_msgTypes[25]
|
mi := &file_tailnet_proto_tailnet_proto_msgTypes[24]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@ -1664,7 +1629,7 @@ func (x *Netcheck_NetcheckIP) String() string {
|
|||||||
func (*Netcheck_NetcheckIP) ProtoMessage() {}
|
func (*Netcheck_NetcheckIP) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *Netcheck_NetcheckIP) ProtoReflect() protoreflect.Message {
|
func (x *Netcheck_NetcheckIP) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_tailnet_proto_tailnet_proto_msgTypes[25]
|
mi := &file_tailnet_proto_tailnet_proto_msgTypes[24]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@ -1677,7 +1642,7 @@ func (x *Netcheck_NetcheckIP) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use Netcheck_NetcheckIP.ProtoReflect.Descriptor instead.
|
// Deprecated: Use Netcheck_NetcheckIP.ProtoReflect.Descriptor instead.
|
||||||
func (*Netcheck_NetcheckIP) Descriptor() ([]byte, []int) {
|
func (*Netcheck_NetcheckIP) Descriptor() ([]byte, []int) {
|
||||||
return file_tailnet_proto_tailnet_proto_rawDescGZIP(), []int{6, 3}
|
return file_tailnet_proto_tailnet_proto_rawDescGZIP(), []int{6, 2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Netcheck_NetcheckIP) GetHash() string {
|
func (x *Netcheck_NetcheckIP) GetHash() string {
|
||||||
@ -1707,7 +1672,7 @@ type TelemetryEvent_P2PEndpoint struct {
|
|||||||
func (x *TelemetryEvent_P2PEndpoint) Reset() {
|
func (x *TelemetryEvent_P2PEndpoint) Reset() {
|
||||||
*x = TelemetryEvent_P2PEndpoint{}
|
*x = TelemetryEvent_P2PEndpoint{}
|
||||||
if protoimpl.UnsafeEnabled {
|
if protoimpl.UnsafeEnabled {
|
||||||
mi := &file_tailnet_proto_tailnet_proto_msgTypes[26]
|
mi := &file_tailnet_proto_tailnet_proto_msgTypes[25]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@ -1720,7 +1685,7 @@ func (x *TelemetryEvent_P2PEndpoint) String() string {
|
|||||||
func (*TelemetryEvent_P2PEndpoint) ProtoMessage() {}
|
func (*TelemetryEvent_P2PEndpoint) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *TelemetryEvent_P2PEndpoint) ProtoReflect() protoreflect.Message {
|
func (x *TelemetryEvent_P2PEndpoint) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_tailnet_proto_tailnet_proto_msgTypes[26]
|
mi := &file_tailnet_proto_tailnet_proto_msgTypes[25]
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@ -1930,218 +1895,191 @@ var file_tailnet_proto_tailnet_proto_rawDesc = []byte{
|
|||||||
0x01, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x49, 0x53, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45,
|
0x01, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x49, 0x53, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45,
|
||||||
0x44, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x4f, 0x53, 0x54, 0x10, 0x03, 0x12, 0x17, 0x0a,
|
0x44, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x4f, 0x53, 0x54, 0x10, 0x03, 0x12, 0x17, 0x0a,
|
||||||
0x13, 0x52, 0x45, 0x41, 0x44, 0x59, 0x5f, 0x46, 0x4f, 0x52, 0x5f, 0x48, 0x41, 0x4e, 0x44, 0x53,
|
0x13, 0x52, 0x45, 0x41, 0x44, 0x59, 0x5f, 0x46, 0x4f, 0x52, 0x5f, 0x48, 0x41, 0x4e, 0x44, 0x53,
|
||||||
0x48, 0x41, 0x4b, 0x45, 0x10, 0x04, 0x22, 0xb2, 0x01, 0x0a, 0x08, 0x49, 0x50, 0x46, 0x69, 0x65,
|
0x48, 0x41, 0x4b, 0x45, 0x10, 0x04, 0x22, 0xa0, 0x01, 0x0a, 0x08, 0x49, 0x50, 0x46, 0x69, 0x65,
|
||||||
0x6c, 0x64, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01,
|
0x6c, 0x64, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01,
|
||||||
0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a,
|
0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a,
|
||||||
0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x63,
|
0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x63,
|
||||||
0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e,
|
0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e,
|
||||||
0x49, 0x50, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x2e, 0x49, 0x50, 0x43, 0x6c, 0x61, 0x73, 0x73,
|
0x49, 0x50, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x2e, 0x49, 0x50, 0x43, 0x6c, 0x61, 0x73, 0x73,
|
||||||
0x52, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x22, 0x52, 0x0a, 0x07, 0x49, 0x50, 0x43, 0x6c, 0x61,
|
0x52, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x22, 0x40, 0x0a, 0x07, 0x49, 0x50, 0x43, 0x6c, 0x61,
|
||||||
0x73, 0x73, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, 0x00, 0x12, 0x0b,
|
0x73, 0x73, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, 0x00, 0x12, 0x0b,
|
||||||
0x0a, 0x07, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x4c,
|
0x0a, 0x07, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x4c,
|
||||||
0x49, 0x4e, 0x4b, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x55,
|
0x49, 0x4e, 0x4b, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x4c,
|
||||||
0x4e, 0x49, 0x51, 0x55, 0x45, 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x03, 0x12, 0x0c, 0x0a,
|
0x4f, 0x4f, 0x50, 0x42, 0x41, 0x43, 0x4b, 0x10, 0x03, 0x22, 0xec, 0x08, 0x0a, 0x08, 0x4e, 0x65,
|
||||||
0x08, 0x4c, 0x4f, 0x4f, 0x50, 0x42, 0x41, 0x43, 0x4b, 0x10, 0x04, 0x22, 0xc4, 0x0a, 0x0a, 0x08,
|
0x74, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x18, 0x01, 0x20,
|
||||||
0x4e, 0x65, 0x74, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x18,
|
0x01, 0x28, 0x08, 0x52, 0x03, 0x55, 0x44, 0x50, 0x12, 0x12, 0x0a, 0x04, 0x49, 0x50, 0x76, 0x36,
|
||||||
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x55, 0x44, 0x50, 0x12, 0x12, 0x0a, 0x04, 0x49, 0x50,
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x49, 0x50, 0x76, 0x36, 0x12, 0x12, 0x0a, 0x04,
|
||||||
0x76, 0x36, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x49, 0x50, 0x76, 0x36, 0x12, 0x12,
|
0x49, 0x50, 0x76, 0x34, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x49, 0x50, 0x76, 0x34,
|
||||||
0x0a, 0x04, 0x49, 0x50, 0x76, 0x34, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x49, 0x50,
|
0x12, 0x20, 0x0a, 0x0b, 0x49, 0x50, 0x76, 0x36, 0x43, 0x61, 0x6e, 0x53, 0x65, 0x6e, 0x64, 0x18,
|
||||||
0x76, 0x34, 0x12, 0x20, 0x0a, 0x0b, 0x49, 0x50, 0x76, 0x36, 0x43, 0x61, 0x6e, 0x53, 0x65, 0x6e,
|
0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x49, 0x50, 0x76, 0x36, 0x43, 0x61, 0x6e, 0x53, 0x65,
|
||||||
0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x49, 0x50, 0x76, 0x36, 0x43, 0x61, 0x6e,
|
0x6e, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x49, 0x50, 0x76, 0x34, 0x43, 0x61, 0x6e, 0x53, 0x65, 0x6e,
|
||||||
0x53, 0x65, 0x6e, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x49, 0x50, 0x76, 0x34, 0x43, 0x61, 0x6e, 0x53,
|
0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x49, 0x50, 0x76, 0x34, 0x43, 0x61, 0x6e,
|
||||||
0x65, 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x49, 0x50, 0x76, 0x34, 0x43,
|
0x53, 0x65, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x49, 0x43, 0x4d, 0x50, 0x76, 0x34, 0x18, 0x06,
|
||||||
0x61, 0x6e, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x4f, 0x53, 0x48, 0x61, 0x73, 0x49,
|
0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x49, 0x43, 0x4d, 0x50, 0x76, 0x34, 0x12, 0x38, 0x0a, 0x09,
|
||||||
0x50, 0x76, 0x36, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x4f, 0x53, 0x48, 0x61, 0x73,
|
0x4f, 0x53, 0x48, 0x61, 0x73, 0x49, 0x50, 0x76, 0x36, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||||
0x49, 0x50, 0x76, 0x36, 0x12, 0x16, 0x0a, 0x06, 0x49, 0x43, 0x4d, 0x50, 0x76, 0x34, 0x18, 0x07,
|
0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x49, 0x43, 0x4d, 0x50, 0x76, 0x34, 0x12, 0x50, 0x0a, 0x15,
|
0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x09, 0x4f, 0x53, 0x48,
|
||||||
0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x72, 0x69, 0x65, 0x73, 0x42, 0x79, 0x44,
|
0x61, 0x73, 0x49, 0x50, 0x76, 0x36, 0x12, 0x50, 0x0a, 0x15, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e,
|
||||||
0x65, 0x73, 0x74, 0x49, 0x50, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
|
0x67, 0x56, 0x61, 0x72, 0x69, 0x65, 0x73, 0x42, 0x79, 0x44, 0x65, 0x73, 0x74, 0x49, 0x50, 0x18,
|
||||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f,
|
0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
|
||||||
0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x15, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67,
|
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75,
|
||||||
0x56, 0x61, 0x72, 0x69, 0x65, 0x73, 0x42, 0x79, 0x44, 0x65, 0x73, 0x74, 0x49, 0x50, 0x12, 0x3c,
|
0x65, 0x52, 0x15, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x72, 0x69, 0x65, 0x73,
|
||||||
0x0a, 0x0b, 0x48, 0x61, 0x69, 0x72, 0x50, 0x69, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x09, 0x20,
|
0x42, 0x79, 0x44, 0x65, 0x73, 0x74, 0x49, 0x50, 0x12, 0x3c, 0x0a, 0x0b, 0x48, 0x61, 0x69, 0x72,
|
||||||
|
0x50, 0x69, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
|
||||||
|
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
||||||
|
0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0b, 0x48, 0x61, 0x69, 0x72, 0x50,
|
||||||
|
0x69, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x2e, 0x0a, 0x04, 0x55, 0x50, 0x6e, 0x50, 0x18, 0x0a,
|
||||||
|
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
||||||
|
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65,
|
||||||
|
0x52, 0x04, 0x55, 0x50, 0x6e, 0x50, 0x12, 0x2c, 0x0a, 0x03, 0x50, 0x4d, 0x50, 0x18, 0x0b, 0x20,
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52,
|
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52,
|
||||||
0x0b, 0x48, 0x61, 0x69, 0x72, 0x50, 0x69, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x2e, 0x0a, 0x04,
|
0x03, 0x50, 0x4d, 0x50, 0x12, 0x2c, 0x0a, 0x03, 0x50, 0x43, 0x50, 0x18, 0x0c, 0x20, 0x01, 0x28,
|
||||||
0x55, 0x50, 0x6e, 0x50, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
|
0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f,
|
0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x50,
|
||||||
0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x55, 0x50, 0x6e, 0x50, 0x12, 0x2c, 0x0a, 0x03,
|
0x43, 0x50, 0x12, 0x24, 0x0a, 0x0d, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x44,
|
||||||
0x50, 0x4d, 0x50, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
0x45, 0x52, 0x50, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x50, 0x72, 0x65, 0x66, 0x65,
|
||||||
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c,
|
0x72, 0x72, 0x65, 0x64, 0x44, 0x45, 0x52, 0x50, 0x12, 0x59, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69,
|
||||||
0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x50, 0x4d, 0x50, 0x12, 0x2c, 0x0a, 0x03, 0x50, 0x43,
|
0x6f, 0x6e, 0x56, 0x34, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x0e, 0x20, 0x03, 0x28,
|
||||||
0x50, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65,
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61,
|
0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x65, 0x74, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x52, 0x65,
|
||||||
0x6c, 0x75, 0x65, 0x52, 0x03, 0x50, 0x43, 0x50, 0x12, 0x24, 0x0a, 0x0d, 0x50, 0x72, 0x65, 0x66,
|
0x67, 0x69, 0x6f, 0x6e, 0x56, 0x34, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x45, 0x6e, 0x74,
|
||||||
0x65, 0x72, 0x72, 0x65, 0x64, 0x44, 0x45, 0x52, 0x50, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52,
|
0x72, 0x79, 0x52, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x56, 0x34, 0x4c, 0x61, 0x74, 0x65,
|
||||||
0x0d, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x44, 0x45, 0x52, 0x50, 0x12, 0x53,
|
0x6e, 0x63, 0x79, 0x12, 0x59, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x56, 0x36, 0x4c,
|
||||||
0x0a, 0x0d, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18,
|
|
||||||
0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61,
|
|
||||||
0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x65, 0x74, 0x63, 0x68, 0x65, 0x63,
|
|
||||||
0x6b, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x45,
|
|
||||||
0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x4c, 0x61, 0x74, 0x65,
|
|
||||||
0x6e, 0x63, 0x79, 0x12, 0x59, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x56, 0x34, 0x4c,
|
|
||||||
0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63,
|
0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63,
|
||||||
0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e,
|
0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e,
|
||||||
0x4e, 0x65, 0x74, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x56,
|
0x4e, 0x65, 0x74, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x56,
|
||||||
0x34, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x52,
|
0x36, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x52,
|
||||||
0x65, 0x67, 0x69, 0x6f, 0x6e, 0x56, 0x34, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x59,
|
0x65, 0x67, 0x69, 0x6f, 0x6e, 0x56, 0x36, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x41,
|
||||||
0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x56, 0x36, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63,
|
0x0a, 0x08, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x56, 0x34, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b,
|
||||||
0x79, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e,
|
0x32, 0x25, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74,
|
||||||
0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x65, 0x74, 0x63, 0x68,
|
0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x65, 0x74, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x4e, 0x65, 0x74,
|
||||||
0x65, 0x63, 0x6b, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x56, 0x36, 0x4c, 0x61, 0x74, 0x65,
|
0x63, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x50, 0x52, 0x08, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x56,
|
||||||
0x6e, 0x63, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e,
|
0x34, 0x12, 0x41, 0x0a, 0x08, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x56, 0x36, 0x18, 0x12, 0x20,
|
||||||
0x56, 0x36, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x41, 0x0a, 0x08, 0x47, 0x6c, 0x6f,
|
0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c,
|
||||||
0x62, 0x61, 0x6c, 0x56, 0x34, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6f,
|
0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x65, 0x74, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2e,
|
||||||
0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4e,
|
0x4e, 0x65, 0x74, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x50, 0x52, 0x08, 0x47, 0x6c, 0x6f, 0x62,
|
||||||
0x65, 0x74, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x4e, 0x65, 0x74, 0x63, 0x68, 0x65, 0x63, 0x6b,
|
0x61, 0x6c, 0x56, 0x36, 0x1a, 0x5d, 0x0a, 0x14, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x56, 0x34,
|
||||||
0x49, 0x50, 0x52, 0x08, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x56, 0x34, 0x12, 0x41, 0x0a, 0x08,
|
0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
|
||||||
0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x56, 0x36, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25,
|
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2f,
|
||||||
0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76,
|
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e,
|
||||||
0x32, 0x2e, 0x4e, 0x65, 0x74, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x2e, 0x4e, 0x65, 0x74, 0x63, 0x68,
|
|
||||||
0x65, 0x63, 0x6b, 0x49, 0x50, 0x52, 0x08, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x56, 0x36, 0x12,
|
|
||||||
0x40, 0x0a, 0x0d, 0x43, 0x61, 0x70, 0x74, 0x69, 0x76, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x61, 0x6c,
|
|
||||||
0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c,
|
|
||||||
0x75, 0x65, 0x52, 0x0d, 0x43, 0x61, 0x70, 0x74, 0x69, 0x76, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x61,
|
|
||||||
0x6c, 0x1a, 0x5b, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x4c, 0x61, 0x74, 0x65, 0x6e,
|
|
||||||
0x63, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
|
|
||||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x05, 0x76, 0x61, 0x6c,
|
|
||||||
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
|
||||||
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74,
|
|
||||||
0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x5d,
|
|
||||||
0x0a, 0x14, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x56, 0x34, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63,
|
|
||||||
0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
|
|
||||||
0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
|
|
||||||
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69,
|
|
||||||
0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x5d, 0x0a,
|
|
||||||
0x14, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x56, 0x36, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79,
|
|
||||||
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
|
|
||||||
0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
|
|
||||||
0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x54, 0x0a, 0x0a,
|
|
||||||
0x4e, 0x65, 0x74, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x50, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61,
|
|
||||||
0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x32,
|
|
||||||
0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
|
|
||||||
0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76,
|
|
||||||
0x32, 0x2e, 0x49, 0x50, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c,
|
|
||||||
0x64, 0x73, 0x22, 0xff, 0x0a, 0x0a, 0x0e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79,
|
|
||||||
0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
|
||||||
0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20,
|
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
|
||||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
|
|
||||||
0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61,
|
|
||||||
0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x70, 0x70, 0x6c,
|
|
||||||
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
|
|
||||||
0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e,
|
|
||||||
0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x65, 0x6c, 0x65, 0x6d,
|
|
||||||
0x65, 0x74, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
|
||||||
0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x69, 0x73, 0x63,
|
|
||||||
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e,
|
|
||||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
|
|
||||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x4c, 0x0a, 0x0b, 0x63,
|
|
||||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e,
|
|
||||||
0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74,
|
|
||||||
0x2e, 0x76, 0x32, 0x2e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x45, 0x76, 0x65,
|
|
||||||
0x6e, 0x74, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x63,
|
|
||||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x6e, 0x6f, 0x64,
|
|
||||||
0x65, 0x5f, 0x69, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x66, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52,
|
|
||||||
0x0a, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x53, 0x65, 0x6c, 0x66, 0x12, 0x24, 0x0a, 0x0e, 0x6e,
|
|
||||||
0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x18, 0x08, 0x20,
|
|
||||||
0x01, 0x28, 0x04, 0x52, 0x0c, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x52, 0x65, 0x6d, 0x6f, 0x74,
|
|
||||||
0x65, 0x12, 0x4f, 0x0a, 0x0c, 0x70, 0x32, 0x70, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
|
|
||||||
0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e,
|
|
||||||
0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x65, 0x6c, 0x65, 0x6d,
|
|
||||||
0x65, 0x74, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x32, 0x50, 0x45, 0x6e, 0x64,
|
|
||||||
0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0b, 0x70, 0x32, 0x70, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69,
|
|
||||||
0x6e, 0x74, 0x12, 0x55, 0x0a, 0x0d, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x70, 0x5f, 0x68, 0x61, 0x73,
|
|
||||||
0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x63, 0x6f, 0x64, 0x65,
|
|
||||||
0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x65, 0x6c,
|
|
||||||
0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x4c, 0x6f, 0x67, 0x49,
|
|
||||||
0x70, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x6c, 0x6f,
|
|
||||||
0x67, 0x49, 0x70, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x6f, 0x6d,
|
|
||||||
0x65, 0x5f, 0x64, 0x65, 0x72, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f,
|
|
||||||
0x6d, 0x65, 0x44, 0x65, 0x72, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x0c,
|
|
||||||
0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x34, 0x0a, 0x08, 0x64, 0x65,
|
|
||||||
0x72, 0x70, 0x5f, 0x6d, 0x61, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63,
|
|
||||||
0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e,
|
|
||||||
0x44, 0x45, 0x52, 0x50, 0x4d, 0x61, 0x70, 0x52, 0x07, 0x64, 0x65, 0x72, 0x70, 0x4d, 0x61, 0x70,
|
|
||||||
0x12, 0x43, 0x0a, 0x0f, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x6e, 0x65, 0x74, 0x63, 0x68,
|
|
||||||
0x65, 0x63, 0x6b, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x64, 0x65,
|
|
||||||
0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x65, 0x74,
|
|
||||||
0x63, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x0e, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x74,
|
|
||||||
0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x40, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
|
|
||||||
0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x67, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e,
|
|
||||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
||||||
0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
|
||||||
0x74, 0x69, 0x6f, 0x6e, 0x41, 0x67, 0x65, 0x12, 0x44, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
|
0x02, 0x38, 0x01, 0x1a, 0x5d, 0x0a, 0x14, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x56, 0x36, 0x4c,
|
||||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x74, 0x75, 0x70, 0x18, 0x10, 0x20, 0x01, 0x28,
|
0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
|
||||||
0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2f, 0x0a,
|
||||||
0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x63, 0x6f,
|
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67,
|
||||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x75, 0x70, 0x12, 0x36, 0x0a,
|
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44,
|
||||||
0x09, 0x70, 0x32, 0x70, 0x5f, 0x73, 0x65, 0x74, 0x75, 0x70, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b,
|
0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
|
||||||
0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
0x38, 0x01, 0x1a, 0x54, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x50,
|
||||||
0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x70, 0x32, 0x70,
|
0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
|
||||||
0x53, 0x65, 0x74, 0x75, 0x70, 0x12, 0x3c, 0x0a, 0x0c, 0x64, 0x65, 0x72, 0x70, 0x5f, 0x6c, 0x61,
|
0x68, 0x61, 0x73, 0x68, 0x12, 0x32, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x02,
|
||||||
0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f,
|
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69,
|
||||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75,
|
0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x49, 0x50, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73,
|
||||||
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x72, 0x70, 0x4c, 0x61, 0x74, 0x65,
|
0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x22, 0xb8, 0x09, 0x0a, 0x0e, 0x54, 0x65, 0x6c,
|
||||||
0x6e, 0x63, 0x79, 0x12, 0x3a, 0x0a, 0x0b, 0x70, 0x32, 0x70, 0x5f, 0x6c, 0x61, 0x74, 0x65, 0x6e,
|
0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
||||||
0x63, 0x79, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x74,
|
||||||
|
0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||||
|
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
|
||||||
|
0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x61,
|
||||||
|
0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
|
||||||
|
0x52, 0x0b, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a,
|
||||||
|
0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e,
|
||||||
|
0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32,
|
||||||
|
0x2e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e,
|
||||||
|
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x31,
|
||||||
|
0x0a, 0x14, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
|
||||||
|
0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x64, 0x69,
|
||||||
|
0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f,
|
||||||
|
0x6e, 0x12, 0x4c, 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65,
|
||||||
|
0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74,
|
||||||
|
0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65,
|
||||||
|
0x74, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54,
|
||||||
|
0x79, 0x70, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12,
|
||||||
|
0x20, 0x0a, 0x0c, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x73, 0x65, 0x6c, 0x66, 0x18,
|
||||||
|
0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x53, 0x65, 0x6c,
|
||||||
|
0x66, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x72, 0x65, 0x6d,
|
||||||
|
0x6f, 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6e, 0x6f, 0x64, 0x65, 0x49,
|
||||||
|
0x64, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x12, 0x4f, 0x0a, 0x0c, 0x70, 0x32, 0x70, 0x5f, 0x65,
|
||||||
|
0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e,
|
||||||
|
0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32,
|
||||||
|
0x2e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e,
|
||||||
|
0x50, 0x32, 0x50, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0b, 0x70, 0x32, 0x70,
|
||||||
|
0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x6f, 0x6d, 0x65,
|
||||||
|
0x5f, 0x64, 0x65, 0x72, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x6d,
|
||||||
|
0x65, 0x44, 0x65, 0x72, 0x70, 0x12, 0x34, 0x0a, 0x08, 0x64, 0x65, 0x72, 0x70, 0x5f, 0x6d, 0x61,
|
||||||
|
0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e,
|
||||||
|
0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x45, 0x52, 0x50, 0x4d,
|
||||||
|
0x61, 0x70, 0x52, 0x07, 0x64, 0x65, 0x72, 0x70, 0x4d, 0x61, 0x70, 0x12, 0x43, 0x0a, 0x0f, 0x6c,
|
||||||
|
0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x6e, 0x65, 0x74, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x0c,
|
||||||
|
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69,
|
||||||
|
0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x65, 0x74, 0x63, 0x68, 0x65, 0x63, 0x6b,
|
||||||
|
0x52, 0x0e, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x4e, 0x65, 0x74, 0x63, 0x68, 0x65, 0x63, 0x6b,
|
||||||
|
0x12, 0x40, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61,
|
||||||
|
0x67, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||||
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74,
|
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74,
|
||||||
0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x32, 0x70, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12,
|
0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41,
|
||||||
0x46, 0x0a, 0x10, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x70, 0x75, 0x74, 0x5f, 0x6d, 0x62,
|
0x67, 0x65, 0x12, 0x44, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||||
0x69, 0x74, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
0x5f, 0x73, 0x65, 0x74, 0x75, 0x70, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67,
|
||||||
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x6c, 0x6f, 0x61,
|
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44,
|
||||||
0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x70,
|
0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
|
||||||
0x75, 0x74, 0x4d, 0x62, 0x69, 0x74, 0x73, 0x1a, 0x69, 0x0a, 0x0b, 0x50, 0x32, 0x50, 0x45, 0x6e,
|
0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x75, 0x70, 0x12, 0x36, 0x0a, 0x09, 0x70, 0x32, 0x70, 0x5f,
|
||||||
0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01,
|
0x73, 0x65, 0x74, 0x75, 0x70, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f,
|
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75,
|
||||||
0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x32,
|
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x70, 0x32, 0x70, 0x53, 0x65, 0x74, 0x75, 0x70,
|
||||||
0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
|
0x12, 0x3c, 0x0a, 0x0c, 0x64, 0x65, 0x72, 0x70, 0x5f, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79,
|
||||||
|
0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||||
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
|
||||||
|
0x6e, 0x52, 0x0b, 0x64, 0x65, 0x72, 0x70, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x3a,
|
||||||
|
0x0a, 0x0b, 0x70, 0x32, 0x70, 0x5f, 0x6c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x11, 0x20,
|
||||||
|
0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
|
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a,
|
||||||
|
0x70, 0x32, 0x70, 0x4c, 0x61, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x46, 0x0a, 0x10, 0x74, 0x68,
|
||||||
|
0x72, 0x6f, 0x75, 0x67, 0x68, 0x70, 0x75, 0x74, 0x5f, 0x6d, 0x62, 0x69, 0x74, 0x73, 0x18, 0x12,
|
||||||
|
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
||||||
|
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75,
|
||||||
|
0x65, 0x52, 0x0f, 0x74, 0x68, 0x72, 0x6f, 0x75, 0x67, 0x68, 0x70, 0x75, 0x74, 0x4d, 0x62, 0x69,
|
||||||
|
0x74, 0x73, 0x1a, 0x69, 0x0a, 0x0b, 0x50, 0x32, 0x50, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
|
||||||
|
0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
|
0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20,
|
||||||
|
0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x32, 0x0a, 0x06, 0x66, 0x69, 0x65,
|
||||||
|
0x6c, 0x64, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x64, 0x65,
|
||||||
|
0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x49, 0x50, 0x46,
|
||||||
|
0x69, 0x65, 0x6c, 0x64, 0x73, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x22, 0x29, 0x0a,
|
||||||
|
0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4e, 0x4e, 0x45,
|
||||||
|
0x43, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x49, 0x53, 0x43, 0x4f, 0x4e,
|
||||||
|
0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x01, 0x22, 0x39, 0x0a, 0x0a, 0x43, 0x6c, 0x69, 0x65,
|
||||||
|
0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x43, 0x4c, 0x49, 0x10, 0x00, 0x12,
|
||||||
|
0x09, 0x0a, 0x05, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f,
|
||||||
|
0x44, 0x45, 0x52, 0x44, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x53, 0x50, 0x52, 0x4f, 0x58,
|
||||||
|
0x59, 0x10, 0x03, 0x22, 0x4c, 0x0a, 0x10, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79,
|
||||||
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74,
|
||||||
|
0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e,
|
||||||
|
0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x65, 0x6c, 0x65, 0x6d,
|
||||||
|
0x65, 0x74, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74,
|
||||||
|
0x73, 0x22, 0x13, 0x0a, 0x11, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x52, 0x65,
|
||||||
|
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x98, 0x02, 0x0a, 0x07, 0x54, 0x61, 0x69, 0x6c, 0x6e,
|
||||||
|
0x65, 0x74, 0x12, 0x58, 0x0a, 0x0d, 0x50, 0x6f, 0x73, 0x74, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65,
|
||||||
|
0x74, 0x72, 0x79, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c,
|
||||||
|
0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79,
|
||||||
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e,
|
||||||
|
0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x65, 0x6c, 0x65, 0x6d,
|
||||||
|
0x65, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x0e,
|
||||||
|
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x44, 0x45, 0x52, 0x50, 0x4d, 0x61, 0x70, 0x73, 0x12, 0x27,
|
||||||
0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76,
|
0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76,
|
||||||
0x32, 0x2e, 0x49, 0x50, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c,
|
0x32, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x44, 0x45, 0x52, 0x50, 0x4d, 0x61, 0x70, 0x73,
|
||||||
0x64, 0x73, 0x1a, 0x5a, 0x0a, 0x10, 0x4c, 0x6f, 0x67, 0x49, 0x70, 0x48, 0x61, 0x73, 0x68, 0x65,
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e,
|
||||||
0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
|
0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x45, 0x52, 0x50, 0x4d,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
|
0x61, 0x70, 0x30, 0x01, 0x12, 0x5b, 0x0a, 0x0a, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61,
|
||||||
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e,
|
0x74, 0x65, 0x12, 0x23, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e,
|
||||||
0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x49, 0x50, 0x46, 0x69, 0x65,
|
0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65,
|
||||||
0x6c, 0x64, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x29,
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e,
|
||||||
0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4e, 0x4e,
|
0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6f, 0x72, 0x64,
|
||||||
0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x49, 0x53, 0x43, 0x4f,
|
0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30,
|
||||||
0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x01, 0x22, 0x39, 0x0a, 0x0a, 0x43, 0x6c, 0x69,
|
0x01, 0x42, 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||||
0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x43, 0x4c, 0x49, 0x10, 0x00,
|
0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x74,
|
||||||
0x12, 0x09, 0x0a, 0x05, 0x41, 0x47, 0x45, 0x4e, 0x54, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x43,
|
0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72,
|
||||||
0x4f, 0x44, 0x45, 0x52, 0x44, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x53, 0x50, 0x52, 0x4f,
|
0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x58, 0x59, 0x10, 0x03, 0x22, 0x4c, 0x0a, 0x10, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72,
|
|
||||||
0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e,
|
|
||||||
0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72,
|
|
||||||
0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x65, 0x6c, 0x65,
|
|
||||||
0x6d, 0x65, 0x74, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e,
|
|
||||||
0x74, 0x73, 0x22, 0x13, 0x0a, 0x11, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x52,
|
|
||||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x98, 0x02, 0x0a, 0x07, 0x54, 0x61, 0x69, 0x6c,
|
|
||||||
0x6e, 0x65, 0x74, 0x12, 0x58, 0x0a, 0x0d, 0x50, 0x6f, 0x73, 0x74, 0x54, 0x65, 0x6c, 0x65, 0x6d,
|
|
||||||
0x65, 0x74, 0x72, 0x79, 0x12, 0x22, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69,
|
|
||||||
0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72,
|
|
||||||
0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72,
|
|
||||||
0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x65, 0x6c, 0x65,
|
|
||||||
0x6d, 0x65, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a,
|
|
||||||
0x0e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x44, 0x45, 0x52, 0x50, 0x4d, 0x61, 0x70, 0x73, 0x12,
|
|
||||||
0x27, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e,
|
|
||||||
0x76, 0x32, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x44, 0x45, 0x52, 0x50, 0x4d, 0x61, 0x70,
|
|
||||||
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72,
|
|
||||||
0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x45, 0x52, 0x50,
|
|
||||||
0x4d, 0x61, 0x70, 0x30, 0x01, 0x12, 0x5b, 0x0a, 0x0a, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e,
|
|
||||||
0x61, 0x74, 0x65, 0x12, 0x23, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2e, 0x74, 0x61, 0x69, 0x6c,
|
|
||||||
0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74,
|
|
||||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x72,
|
|
||||||
0x2e, 0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6f, 0x72,
|
|
||||||
0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01,
|
|
||||||
0x30, 0x01, 0x42, 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
|
||||||
0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f,
|
|
||||||
0x74, 0x61, 0x69, 0x6c, 0x6e, 0x65, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70,
|
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -2157,7 +2095,7 @@ func file_tailnet_proto_tailnet_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_tailnet_proto_tailnet_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
|
var file_tailnet_proto_tailnet_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
|
||||||
var file_tailnet_proto_tailnet_proto_msgTypes = make([]protoimpl.MessageInfo, 28)
|
var file_tailnet_proto_tailnet_proto_msgTypes = make([]protoimpl.MessageInfo, 26)
|
||||||
var file_tailnet_proto_tailnet_proto_goTypes = []interface{}{
|
var file_tailnet_proto_tailnet_proto_goTypes = []interface{}{
|
||||||
(CoordinateResponse_PeerUpdate_Kind)(0), // 0: coder.tailnet.v2.CoordinateResponse.PeerUpdate.Kind
|
(CoordinateResponse_PeerUpdate_Kind)(0), // 0: coder.tailnet.v2.CoordinateResponse.PeerUpdate.Kind
|
||||||
(IPFields_IPClass)(0), // 1: coder.tailnet.v2.IPFields.IPClass
|
(IPFields_IPClass)(0), // 1: coder.tailnet.v2.IPFields.IPClass
|
||||||
@ -2185,21 +2123,19 @@ var file_tailnet_proto_tailnet_proto_goTypes = []interface{}{
|
|||||||
(*CoordinateRequest_Tunnel)(nil), // 23: coder.tailnet.v2.CoordinateRequest.Tunnel
|
(*CoordinateRequest_Tunnel)(nil), // 23: coder.tailnet.v2.CoordinateRequest.Tunnel
|
||||||
(*CoordinateRequest_ReadyForHandshake)(nil), // 24: coder.tailnet.v2.CoordinateRequest.ReadyForHandshake
|
(*CoordinateRequest_ReadyForHandshake)(nil), // 24: coder.tailnet.v2.CoordinateRequest.ReadyForHandshake
|
||||||
(*CoordinateResponse_PeerUpdate)(nil), // 25: coder.tailnet.v2.CoordinateResponse.PeerUpdate
|
(*CoordinateResponse_PeerUpdate)(nil), // 25: coder.tailnet.v2.CoordinateResponse.PeerUpdate
|
||||||
nil, // 26: coder.tailnet.v2.Netcheck.RegionLatencyEntry
|
nil, // 26: coder.tailnet.v2.Netcheck.RegionV4LatencyEntry
|
||||||
nil, // 27: coder.tailnet.v2.Netcheck.RegionV4LatencyEntry
|
nil, // 27: coder.tailnet.v2.Netcheck.RegionV6LatencyEntry
|
||||||
nil, // 28: coder.tailnet.v2.Netcheck.RegionV6LatencyEntry
|
(*Netcheck_NetcheckIP)(nil), // 28: coder.tailnet.v2.Netcheck.NetcheckIP
|
||||||
(*Netcheck_NetcheckIP)(nil), // 29: coder.tailnet.v2.Netcheck.NetcheckIP
|
(*TelemetryEvent_P2PEndpoint)(nil), // 29: coder.tailnet.v2.TelemetryEvent.P2PEndpoint
|
||||||
(*TelemetryEvent_P2PEndpoint)(nil), // 30: coder.tailnet.v2.TelemetryEvent.P2PEndpoint
|
(*timestamppb.Timestamp)(nil), // 30: google.protobuf.Timestamp
|
||||||
nil, // 31: coder.tailnet.v2.TelemetryEvent.LogIpHashesEntry
|
(*wrapperspb.BoolValue)(nil), // 31: google.protobuf.BoolValue
|
||||||
(*timestamppb.Timestamp)(nil), // 32: google.protobuf.Timestamp
|
(*durationpb.Duration)(nil), // 32: google.protobuf.Duration
|
||||||
(*wrapperspb.BoolValue)(nil), // 33: google.protobuf.BoolValue
|
(*wrapperspb.FloatValue)(nil), // 33: google.protobuf.FloatValue
|
||||||
(*durationpb.Duration)(nil), // 34: google.protobuf.Duration
|
|
||||||
(*wrapperspb.FloatValue)(nil), // 35: google.protobuf.FloatValue
|
|
||||||
}
|
}
|
||||||
var file_tailnet_proto_tailnet_proto_depIdxs = []int32{
|
var file_tailnet_proto_tailnet_proto_depIdxs = []int32{
|
||||||
14, // 0: coder.tailnet.v2.DERPMap.home_params:type_name -> coder.tailnet.v2.DERPMap.HomeParams
|
14, // 0: coder.tailnet.v2.DERPMap.home_params:type_name -> coder.tailnet.v2.DERPMap.HomeParams
|
||||||
16, // 1: coder.tailnet.v2.DERPMap.regions:type_name -> coder.tailnet.v2.DERPMap.RegionsEntry
|
16, // 1: coder.tailnet.v2.DERPMap.regions:type_name -> coder.tailnet.v2.DERPMap.RegionsEntry
|
||||||
32, // 2: coder.tailnet.v2.Node.as_of:type_name -> google.protobuf.Timestamp
|
30, // 2: coder.tailnet.v2.Node.as_of:type_name -> google.protobuf.Timestamp
|
||||||
19, // 3: coder.tailnet.v2.Node.derp_latency:type_name -> coder.tailnet.v2.Node.DerpLatencyEntry
|
19, // 3: coder.tailnet.v2.Node.derp_latency:type_name -> coder.tailnet.v2.Node.DerpLatencyEntry
|
||||||
20, // 4: coder.tailnet.v2.Node.derp_forced_websocket:type_name -> coder.tailnet.v2.Node.DerpForcedWebsocketEntry
|
20, // 4: coder.tailnet.v2.Node.derp_forced_websocket:type_name -> coder.tailnet.v2.Node.DerpForcedWebsocketEntry
|
||||||
21, // 5: coder.tailnet.v2.CoordinateRequest.update_self:type_name -> coder.tailnet.v2.CoordinateRequest.UpdateSelf
|
21, // 5: coder.tailnet.v2.CoordinateRequest.update_self:type_name -> coder.tailnet.v2.CoordinateRequest.UpdateSelf
|
||||||
@ -2209,54 +2145,50 @@ var file_tailnet_proto_tailnet_proto_depIdxs = []int32{
|
|||||||
24, // 9: coder.tailnet.v2.CoordinateRequest.ready_for_handshake:type_name -> coder.tailnet.v2.CoordinateRequest.ReadyForHandshake
|
24, // 9: coder.tailnet.v2.CoordinateRequest.ready_for_handshake:type_name -> coder.tailnet.v2.CoordinateRequest.ReadyForHandshake
|
||||||
25, // 10: coder.tailnet.v2.CoordinateResponse.peer_updates:type_name -> coder.tailnet.v2.CoordinateResponse.PeerUpdate
|
25, // 10: coder.tailnet.v2.CoordinateResponse.peer_updates:type_name -> coder.tailnet.v2.CoordinateResponse.PeerUpdate
|
||||||
1, // 11: coder.tailnet.v2.IPFields.class:type_name -> coder.tailnet.v2.IPFields.IPClass
|
1, // 11: coder.tailnet.v2.IPFields.class:type_name -> coder.tailnet.v2.IPFields.IPClass
|
||||||
33, // 12: coder.tailnet.v2.Netcheck.MappingVariesByDestIP:type_name -> google.protobuf.BoolValue
|
31, // 12: coder.tailnet.v2.Netcheck.OSHasIPv6:type_name -> google.protobuf.BoolValue
|
||||||
33, // 13: coder.tailnet.v2.Netcheck.HairPinning:type_name -> google.protobuf.BoolValue
|
31, // 13: coder.tailnet.v2.Netcheck.MappingVariesByDestIP:type_name -> google.protobuf.BoolValue
|
||||||
33, // 14: coder.tailnet.v2.Netcheck.UPnP:type_name -> google.protobuf.BoolValue
|
31, // 14: coder.tailnet.v2.Netcheck.HairPinning:type_name -> google.protobuf.BoolValue
|
||||||
33, // 15: coder.tailnet.v2.Netcheck.PMP:type_name -> google.protobuf.BoolValue
|
31, // 15: coder.tailnet.v2.Netcheck.UPnP:type_name -> google.protobuf.BoolValue
|
||||||
33, // 16: coder.tailnet.v2.Netcheck.PCP:type_name -> google.protobuf.BoolValue
|
31, // 16: coder.tailnet.v2.Netcheck.PMP:type_name -> google.protobuf.BoolValue
|
||||||
26, // 17: coder.tailnet.v2.Netcheck.RegionLatency:type_name -> coder.tailnet.v2.Netcheck.RegionLatencyEntry
|
31, // 17: coder.tailnet.v2.Netcheck.PCP:type_name -> google.protobuf.BoolValue
|
||||||
27, // 18: coder.tailnet.v2.Netcheck.RegionV4Latency:type_name -> coder.tailnet.v2.Netcheck.RegionV4LatencyEntry
|
26, // 18: coder.tailnet.v2.Netcheck.RegionV4Latency:type_name -> coder.tailnet.v2.Netcheck.RegionV4LatencyEntry
|
||||||
28, // 19: coder.tailnet.v2.Netcheck.RegionV6Latency:type_name -> coder.tailnet.v2.Netcheck.RegionV6LatencyEntry
|
27, // 19: coder.tailnet.v2.Netcheck.RegionV6Latency:type_name -> coder.tailnet.v2.Netcheck.RegionV6LatencyEntry
|
||||||
29, // 20: coder.tailnet.v2.Netcheck.GlobalV4:type_name -> coder.tailnet.v2.Netcheck.NetcheckIP
|
28, // 20: coder.tailnet.v2.Netcheck.GlobalV4:type_name -> coder.tailnet.v2.Netcheck.NetcheckIP
|
||||||
29, // 21: coder.tailnet.v2.Netcheck.GlobalV6:type_name -> coder.tailnet.v2.Netcheck.NetcheckIP
|
28, // 21: coder.tailnet.v2.Netcheck.GlobalV6:type_name -> coder.tailnet.v2.Netcheck.NetcheckIP
|
||||||
33, // 22: coder.tailnet.v2.Netcheck.CaptivePortal:type_name -> google.protobuf.BoolValue
|
30, // 22: coder.tailnet.v2.TelemetryEvent.time:type_name -> google.protobuf.Timestamp
|
||||||
32, // 23: coder.tailnet.v2.TelemetryEvent.time:type_name -> google.protobuf.Timestamp
|
2, // 23: coder.tailnet.v2.TelemetryEvent.status:type_name -> coder.tailnet.v2.TelemetryEvent.Status
|
||||||
2, // 24: coder.tailnet.v2.TelemetryEvent.status:type_name -> coder.tailnet.v2.TelemetryEvent.Status
|
3, // 24: coder.tailnet.v2.TelemetryEvent.client_type:type_name -> coder.tailnet.v2.TelemetryEvent.ClientType
|
||||||
3, // 25: coder.tailnet.v2.TelemetryEvent.client_type:type_name -> coder.tailnet.v2.TelemetryEvent.ClientType
|
29, // 25: coder.tailnet.v2.TelemetryEvent.p2p_endpoint:type_name -> coder.tailnet.v2.TelemetryEvent.P2PEndpoint
|
||||||
30, // 26: coder.tailnet.v2.TelemetryEvent.p2p_endpoint:type_name -> coder.tailnet.v2.TelemetryEvent.P2PEndpoint
|
4, // 26: coder.tailnet.v2.TelemetryEvent.derp_map:type_name -> coder.tailnet.v2.DERPMap
|
||||||
31, // 27: coder.tailnet.v2.TelemetryEvent.log_ip_hashes:type_name -> coder.tailnet.v2.TelemetryEvent.LogIpHashesEntry
|
10, // 27: coder.tailnet.v2.TelemetryEvent.latest_netcheck:type_name -> coder.tailnet.v2.Netcheck
|
||||||
4, // 28: coder.tailnet.v2.TelemetryEvent.derp_map:type_name -> coder.tailnet.v2.DERPMap
|
32, // 28: coder.tailnet.v2.TelemetryEvent.connection_age:type_name -> google.protobuf.Duration
|
||||||
10, // 29: coder.tailnet.v2.TelemetryEvent.latest_netcheck:type_name -> coder.tailnet.v2.Netcheck
|
32, // 29: coder.tailnet.v2.TelemetryEvent.connection_setup:type_name -> google.protobuf.Duration
|
||||||
34, // 30: coder.tailnet.v2.TelemetryEvent.connection_age:type_name -> google.protobuf.Duration
|
32, // 30: coder.tailnet.v2.TelemetryEvent.p2p_setup:type_name -> google.protobuf.Duration
|
||||||
34, // 31: coder.tailnet.v2.TelemetryEvent.connection_setup:type_name -> google.protobuf.Duration
|
32, // 31: coder.tailnet.v2.TelemetryEvent.derp_latency:type_name -> google.protobuf.Duration
|
||||||
34, // 32: coder.tailnet.v2.TelemetryEvent.p2p_setup:type_name -> google.protobuf.Duration
|
32, // 32: coder.tailnet.v2.TelemetryEvent.p2p_latency:type_name -> google.protobuf.Duration
|
||||||
34, // 33: coder.tailnet.v2.TelemetryEvent.derp_latency:type_name -> google.protobuf.Duration
|
33, // 33: coder.tailnet.v2.TelemetryEvent.throughput_mbits:type_name -> google.protobuf.FloatValue
|
||||||
34, // 34: coder.tailnet.v2.TelemetryEvent.p2p_latency:type_name -> google.protobuf.Duration
|
11, // 34: coder.tailnet.v2.TelemetryRequest.events:type_name -> coder.tailnet.v2.TelemetryEvent
|
||||||
35, // 35: coder.tailnet.v2.TelemetryEvent.throughput_mbits:type_name -> google.protobuf.FloatValue
|
17, // 35: coder.tailnet.v2.DERPMap.HomeParams.region_score:type_name -> coder.tailnet.v2.DERPMap.HomeParams.RegionScoreEntry
|
||||||
11, // 36: coder.tailnet.v2.TelemetryRequest.events:type_name -> coder.tailnet.v2.TelemetryEvent
|
18, // 36: coder.tailnet.v2.DERPMap.Region.nodes:type_name -> coder.tailnet.v2.DERPMap.Region.Node
|
||||||
17, // 37: coder.tailnet.v2.DERPMap.HomeParams.region_score:type_name -> coder.tailnet.v2.DERPMap.HomeParams.RegionScoreEntry
|
15, // 37: coder.tailnet.v2.DERPMap.RegionsEntry.value:type_name -> coder.tailnet.v2.DERPMap.Region
|
||||||
18, // 38: coder.tailnet.v2.DERPMap.Region.nodes:type_name -> coder.tailnet.v2.DERPMap.Region.Node
|
6, // 38: coder.tailnet.v2.CoordinateRequest.UpdateSelf.node:type_name -> coder.tailnet.v2.Node
|
||||||
15, // 39: coder.tailnet.v2.DERPMap.RegionsEntry.value:type_name -> coder.tailnet.v2.DERPMap.Region
|
6, // 39: coder.tailnet.v2.CoordinateResponse.PeerUpdate.node:type_name -> coder.tailnet.v2.Node
|
||||||
6, // 40: coder.tailnet.v2.CoordinateRequest.UpdateSelf.node:type_name -> coder.tailnet.v2.Node
|
0, // 40: coder.tailnet.v2.CoordinateResponse.PeerUpdate.kind:type_name -> coder.tailnet.v2.CoordinateResponse.PeerUpdate.Kind
|
||||||
6, // 41: coder.tailnet.v2.CoordinateResponse.PeerUpdate.node:type_name -> coder.tailnet.v2.Node
|
32, // 41: coder.tailnet.v2.Netcheck.RegionV4LatencyEntry.value:type_name -> google.protobuf.Duration
|
||||||
0, // 42: coder.tailnet.v2.CoordinateResponse.PeerUpdate.kind:type_name -> coder.tailnet.v2.CoordinateResponse.PeerUpdate.Kind
|
32, // 42: coder.tailnet.v2.Netcheck.RegionV6LatencyEntry.value:type_name -> google.protobuf.Duration
|
||||||
34, // 43: coder.tailnet.v2.Netcheck.RegionLatencyEntry.value:type_name -> google.protobuf.Duration
|
9, // 43: coder.tailnet.v2.Netcheck.NetcheckIP.fields:type_name -> coder.tailnet.v2.IPFields
|
||||||
34, // 44: coder.tailnet.v2.Netcheck.RegionV4LatencyEntry.value:type_name -> google.protobuf.Duration
|
9, // 44: coder.tailnet.v2.TelemetryEvent.P2PEndpoint.fields:type_name -> coder.tailnet.v2.IPFields
|
||||||
34, // 45: coder.tailnet.v2.Netcheck.RegionV6LatencyEntry.value:type_name -> google.protobuf.Duration
|
12, // 45: coder.tailnet.v2.Tailnet.PostTelemetry:input_type -> coder.tailnet.v2.TelemetryRequest
|
||||||
9, // 46: coder.tailnet.v2.Netcheck.NetcheckIP.fields:type_name -> coder.tailnet.v2.IPFields
|
5, // 46: coder.tailnet.v2.Tailnet.StreamDERPMaps:input_type -> coder.tailnet.v2.StreamDERPMapsRequest
|
||||||
9, // 47: coder.tailnet.v2.TelemetryEvent.P2PEndpoint.fields:type_name -> coder.tailnet.v2.IPFields
|
7, // 47: coder.tailnet.v2.Tailnet.Coordinate:input_type -> coder.tailnet.v2.CoordinateRequest
|
||||||
9, // 48: coder.tailnet.v2.TelemetryEvent.LogIpHashesEntry.value:type_name -> coder.tailnet.v2.IPFields
|
13, // 48: coder.tailnet.v2.Tailnet.PostTelemetry:output_type -> coder.tailnet.v2.TelemetryResponse
|
||||||
12, // 49: coder.tailnet.v2.Tailnet.PostTelemetry:input_type -> coder.tailnet.v2.TelemetryRequest
|
4, // 49: coder.tailnet.v2.Tailnet.StreamDERPMaps:output_type -> coder.tailnet.v2.DERPMap
|
||||||
5, // 50: coder.tailnet.v2.Tailnet.StreamDERPMaps:input_type -> coder.tailnet.v2.StreamDERPMapsRequest
|
8, // 50: coder.tailnet.v2.Tailnet.Coordinate:output_type -> coder.tailnet.v2.CoordinateResponse
|
||||||
7, // 51: coder.tailnet.v2.Tailnet.Coordinate:input_type -> coder.tailnet.v2.CoordinateRequest
|
48, // [48:51] is the sub-list for method output_type
|
||||||
13, // 52: coder.tailnet.v2.Tailnet.PostTelemetry:output_type -> coder.tailnet.v2.TelemetryResponse
|
45, // [45:48] is the sub-list for method input_type
|
||||||
4, // 53: coder.tailnet.v2.Tailnet.StreamDERPMaps:output_type -> coder.tailnet.v2.DERPMap
|
45, // [45:45] is the sub-list for extension type_name
|
||||||
8, // 54: coder.tailnet.v2.Tailnet.Coordinate:output_type -> coder.tailnet.v2.CoordinateResponse
|
45, // [45:45] is the sub-list for extension extendee
|
||||||
52, // [52:55] is the sub-list for method output_type
|
0, // [0:45] is the sub-list for field type_name
|
||||||
49, // [49:52] is the sub-list for method input_type
|
|
||||||
49, // [49:49] is the sub-list for extension type_name
|
|
||||||
49, // [49:49] is the sub-list for extension extendee
|
|
||||||
0, // [0:49] is the sub-list for field type_name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_tailnet_proto_tailnet_proto_init() }
|
func init() { file_tailnet_proto_tailnet_proto_init() }
|
||||||
@ -2481,7 +2413,7 @@ func file_tailnet_proto_tailnet_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_tailnet_proto_tailnet_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} {
|
file_tailnet_proto_tailnet_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*Netcheck_NetcheckIP); i {
|
switch v := v.(*Netcheck_NetcheckIP); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@ -2493,7 +2425,7 @@ func file_tailnet_proto_tailnet_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_tailnet_proto_tailnet_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} {
|
file_tailnet_proto_tailnet_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*TelemetryEvent_P2PEndpoint); i {
|
switch v := v.(*TelemetryEvent_P2PEndpoint); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@ -2512,7 +2444,7 @@ func file_tailnet_proto_tailnet_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_tailnet_proto_tailnet_proto_rawDesc,
|
RawDescriptor: file_tailnet_proto_tailnet_proto_rawDesc,
|
||||||
NumEnums: 4,
|
NumEnums: 4,
|
||||||
NumMessages: 28,
|
NumMessages: 26,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
|
@ -108,8 +108,7 @@ message IPFields {
|
|||||||
PUBLIC = 0;
|
PUBLIC = 0;
|
||||||
PRIVATE = 1;
|
PRIVATE = 1;
|
||||||
LINK_LOCAL = 2;
|
LINK_LOCAL = 2;
|
||||||
UNIQUE_LOCAL = 3;
|
LOOPBACK = 3;
|
||||||
LOOPBACK = 4;
|
|
||||||
}
|
}
|
||||||
IPClass class = 2;
|
IPClass class = 2;
|
||||||
}
|
}
|
||||||
@ -120,9 +119,9 @@ message Netcheck {
|
|||||||
bool IPv4 = 3;
|
bool IPv4 = 3;
|
||||||
bool IPv6CanSend = 4;
|
bool IPv6CanSend = 4;
|
||||||
bool IPv4CanSend = 5;
|
bool IPv4CanSend = 5;
|
||||||
bool OSHasIPv6 = 6;
|
bool ICMPv4 = 6;
|
||||||
bool ICMPv4 = 7;
|
|
||||||
|
|
||||||
|
google.protobuf.BoolValue OSHasIPv6 = 7;
|
||||||
google.protobuf.BoolValue MappingVariesByDestIP = 8;
|
google.protobuf.BoolValue MappingVariesByDestIP = 8;
|
||||||
google.protobuf.BoolValue HairPinning = 9;
|
google.protobuf.BoolValue HairPinning = 9;
|
||||||
google.protobuf.BoolValue UPnP = 10;
|
google.protobuf.BoolValue UPnP = 10;
|
||||||
@ -131,9 +130,8 @@ message Netcheck {
|
|||||||
|
|
||||||
int64 PreferredDERP = 13; // 0 for unknown
|
int64 PreferredDERP = 13; // 0 for unknown
|
||||||
|
|
||||||
map<int64, google.protobuf.Duration> RegionLatency = 14;
|
map<int64, google.protobuf.Duration> RegionV4Latency = 14;
|
||||||
map<int64, google.protobuf.Duration> RegionV4Latency = 15;
|
map<int64, google.protobuf.Duration> RegionV6Latency = 15;
|
||||||
map<int64, google.protobuf.Duration> RegionV6Latency = 16;
|
|
||||||
|
|
||||||
message NetcheckIP {
|
message NetcheckIP {
|
||||||
string hash = 1;
|
string hash = 1;
|
||||||
@ -141,8 +139,6 @@ message Netcheck {
|
|||||||
}
|
}
|
||||||
NetcheckIP GlobalV4 = 17;
|
NetcheckIP GlobalV4 = 17;
|
||||||
NetcheckIP GlobalV6 = 18;
|
NetcheckIP GlobalV6 = 18;
|
||||||
|
|
||||||
google.protobuf.BoolValue CaptivePortal = 19;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message TelemetryEvent {
|
message TelemetryEvent {
|
||||||
@ -173,18 +169,16 @@ message TelemetryEvent {
|
|||||||
uint64 node_id_self = 7;
|
uint64 node_id_self = 7;
|
||||||
uint64 node_id_remote = 8;
|
uint64 node_id_remote = 8;
|
||||||
P2PEndpoint p2p_endpoint = 9;
|
P2PEndpoint p2p_endpoint = 9;
|
||||||
map<string, IPFields> log_ip_hashes = 10;
|
string home_derp = 10;
|
||||||
string home_derp = 11;
|
DERPMap derp_map = 11;
|
||||||
repeated string logs = 12;
|
Netcheck latest_netcheck = 12;
|
||||||
DERPMap derp_map = 13;
|
|
||||||
Netcheck latest_netcheck = 14;
|
|
||||||
|
|
||||||
google.protobuf.Duration connection_age = 15;
|
google.protobuf.Duration connection_age = 13;
|
||||||
google.protobuf.Duration connection_setup = 16;
|
google.protobuf.Duration connection_setup = 14;
|
||||||
google.protobuf.Duration p2p_setup = 17;
|
google.protobuf.Duration p2p_setup = 15;
|
||||||
google.protobuf.Duration derp_latency = 18;
|
google.protobuf.Duration derp_latency = 16;
|
||||||
google.protobuf.Duration p2p_latency = 19;
|
google.protobuf.Duration p2p_latency = 17;
|
||||||
google.protobuf.FloatValue throughput_mbits = 20;
|
google.protobuf.FloatValue throughput_mbits = 18;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TelemetryRequest {
|
message TelemetryRequest {
|
||||||
|
198
tailnet/telemetry.go
Normal file
198
tailnet/telemetry.go
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
package tailnet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"net/netip"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
"google.golang.org/protobuf/types/known/durationpb"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||||
|
"tailscale.com/tailcfg"
|
||||||
|
|
||||||
|
"github.com/coder/coder/v2/cryptorand"
|
||||||
|
"github.com/coder/coder/v2/tailnet/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TelemetryApplicationSSH string = "ssh"
|
||||||
|
TelemetryApplicationSpeedtest string = "speedtest"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Responsible for storing and anonymizing networking telemetry state.
|
||||||
|
type TelemetryStore struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
hashSalt string
|
||||||
|
// A cache to avoid hashing the same IP or hostname multiple times.
|
||||||
|
hashCache map[string]string
|
||||||
|
|
||||||
|
cleanDerpMap *tailcfg.DERPMap
|
||||||
|
cleanNetCheck *proto.Netcheck
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTelemetryStore() (*TelemetryStore, error) {
|
||||||
|
hashSalt, err := cryptorand.String(16)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &TelemetryStore{
|
||||||
|
hashSalt: hashSalt,
|
||||||
|
hashCache: make(map[string]string),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// newEvent returns the current telemetry state as an event
|
||||||
|
func (b *TelemetryStore) newEvent() *proto.TelemetryEvent {
|
||||||
|
b.mu.Lock()
|
||||||
|
defer b.mu.Unlock()
|
||||||
|
|
||||||
|
return &proto.TelemetryEvent{
|
||||||
|
Time: timestamppb.Now(),
|
||||||
|
DerpMap: DERPMapToProto(b.cleanDerpMap),
|
||||||
|
LatestNetcheck: b.cleanNetCheck,
|
||||||
|
|
||||||
|
// TODO(ethanndickson):
|
||||||
|
ConnectionAge: &durationpb.Duration{},
|
||||||
|
ConnectionSetup: &durationpb.Duration{},
|
||||||
|
P2PSetup: &durationpb.Duration{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a DERPMap, anonymise all IPs and hostnames.
|
||||||
|
// Keep track of seen hostnames/cert names to anonymize them from future logs.
|
||||||
|
// b.mu must NOT be held.
|
||||||
|
func (b *TelemetryStore) updateDerpMap(cur *tailcfg.DERPMap) {
|
||||||
|
b.mu.Lock()
|
||||||
|
defer b.mu.Unlock()
|
||||||
|
cleanMap := cur.Clone()
|
||||||
|
for _, r := range cleanMap.Regions {
|
||||||
|
for _, n := range r.Nodes {
|
||||||
|
ipv4, _, _ := b.processIPLocked(n.IPv4)
|
||||||
|
n.IPv4 = ipv4
|
||||||
|
ipv6, _, _ := b.processIPLocked(n.IPv6)
|
||||||
|
n.IPv6 = ipv6
|
||||||
|
stunIP, _, _ := b.processIPLocked(n.STUNTestIP)
|
||||||
|
n.STUNTestIP = stunIP
|
||||||
|
hn := b.hashAddrorHostname(n.HostName)
|
||||||
|
n.HostName = hn
|
||||||
|
cn := b.hashAddrorHostname(n.CertName)
|
||||||
|
n.CertName = cn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.cleanDerpMap = cleanMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store an anonymized proto.Netcheck given a tailscale NetInfo.
|
||||||
|
func (b *TelemetryStore) setNetInfo(ni *tailcfg.NetInfo) {
|
||||||
|
b.mu.Lock()
|
||||||
|
defer b.mu.Unlock()
|
||||||
|
|
||||||
|
b.cleanNetCheck = &proto.Netcheck{
|
||||||
|
UDP: ni.UDP,
|
||||||
|
IPv6: ni.IPv6,
|
||||||
|
IPv4: ni.IPv4,
|
||||||
|
IPv6CanSend: ni.IPv6CanSend,
|
||||||
|
IPv4CanSend: ni.IPv4CanSend,
|
||||||
|
ICMPv4: ni.ICMPv4,
|
||||||
|
OSHasIPv6: wrapperspb.Bool(ni.OSHasIPv6.EqualBool(true)),
|
||||||
|
MappingVariesByDestIP: wrapperspb.Bool(ni.MappingVariesByDestIP.EqualBool(true)),
|
||||||
|
HairPinning: wrapperspb.Bool(ni.HairPinning.EqualBool(true)),
|
||||||
|
UPnP: wrapperspb.Bool(ni.UPnP.EqualBool(true)),
|
||||||
|
PMP: wrapperspb.Bool(ni.PMP.EqualBool(true)),
|
||||||
|
PCP: wrapperspb.Bool(ni.PCP.EqualBool(true)),
|
||||||
|
PreferredDERP: int64(ni.PreferredDERP),
|
||||||
|
RegionV4Latency: make(map[int64]*durationpb.Duration),
|
||||||
|
RegionV6Latency: make(map[int64]*durationpb.Duration),
|
||||||
|
}
|
||||||
|
v4hash, v4fields, err := b.processIPLocked(ni.GlobalV4)
|
||||||
|
if err == nil {
|
||||||
|
b.cleanNetCheck.GlobalV4 = &proto.Netcheck_NetcheckIP{
|
||||||
|
Hash: v4hash,
|
||||||
|
Fields: v4fields,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v6hash, v6fields, err := b.processIPLocked(ni.GlobalV6)
|
||||||
|
if err == nil {
|
||||||
|
b.cleanNetCheck.GlobalV6 = &proto.Netcheck_NetcheckIP{
|
||||||
|
Hash: v6hash,
|
||||||
|
Fields: v6fields,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for rid, seconds := range ni.DERPLatencyV4 {
|
||||||
|
b.cleanNetCheck.RegionV4Latency[int64(rid)] = durationpb.New(time.Duration(seconds * float64(time.Second)))
|
||||||
|
}
|
||||||
|
for rid, seconds := range ni.DERPLatencyV6 {
|
||||||
|
b.cleanNetCheck.RegionV6Latency[int64(rid)] = durationpb.New(time.Duration(seconds * float64(time.Second)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *TelemetryStore) toEndpoint(ipport string) *proto.TelemetryEvent_P2PEndpoint {
|
||||||
|
b.mu.Lock()
|
||||||
|
defer b.mu.Unlock()
|
||||||
|
|
||||||
|
addrport, err := netip.ParseAddrPort(ipport)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
addr := addrport.Addr()
|
||||||
|
fields := addrToFields(addr)
|
||||||
|
hashStr := b.hashAddrorHostname(addr.String())
|
||||||
|
return &proto.TelemetryEvent_P2PEndpoint{
|
||||||
|
Hash: hashStr,
|
||||||
|
Port: int32(addrport.Port()),
|
||||||
|
Fields: fields,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// processIPLocked will look up the IP in the cache, or hash and salt it and add
|
||||||
|
// to the cache. It will also add it to hashedIPs.
|
||||||
|
//
|
||||||
|
// b.mu must be held.
|
||||||
|
func (b *TelemetryStore) processIPLocked(ip string) (string, *proto.IPFields, error) {
|
||||||
|
addr, err := netip.ParseAddr(ip)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, xerrors.Errorf("failed to parse IP %q: %w", ip, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := addrToFields(addr)
|
||||||
|
hashStr := b.hashAddrorHostname(ip)
|
||||||
|
return hashStr, fields, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *TelemetryStore) hashAddrorHostname(addr string) string {
|
||||||
|
if hashStr, ok := b.hashCache[addr]; ok {
|
||||||
|
return hashStr
|
||||||
|
}
|
||||||
|
|
||||||
|
hash := sha256.Sum256([]byte(b.hashSalt + addr))
|
||||||
|
hashStr := hex.EncodeToString(hash[:])
|
||||||
|
b.hashCache[addr] = hashStr
|
||||||
|
return hashStr
|
||||||
|
}
|
||||||
|
|
||||||
|
func addrToFields(addr netip.Addr) *proto.IPFields {
|
||||||
|
version := int32(4)
|
||||||
|
if addr.Is6() {
|
||||||
|
version = 6
|
||||||
|
}
|
||||||
|
|
||||||
|
class := proto.IPFields_PUBLIC
|
||||||
|
switch {
|
||||||
|
case addr.IsLoopback():
|
||||||
|
class = proto.IPFields_LOOPBACK
|
||||||
|
case addr.IsLinkLocalUnicast():
|
||||||
|
class = proto.IPFields_LINK_LOCAL
|
||||||
|
case addr.IsLinkLocalMulticast():
|
||||||
|
class = proto.IPFields_LINK_LOCAL
|
||||||
|
case addr.IsPrivate():
|
||||||
|
class = proto.IPFields_PRIVATE
|
||||||
|
}
|
||||||
|
|
||||||
|
return &proto.IPFields{
|
||||||
|
Version: version,
|
||||||
|
Class: class,
|
||||||
|
}
|
||||||
|
}
|
151
tailnet/telemetry_internal_test.go
Normal file
151
tailnet/telemetry_internal_test.go
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package tailnet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"tailscale.com/tailcfg"
|
||||||
|
|
||||||
|
"github.com/coder/coder/v2/tailnet/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTelemetryStore(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
t.Run("CleanIPs", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
ipv4 string
|
||||||
|
ipv6 string
|
||||||
|
expectedVersion int32
|
||||||
|
expectedClass proto.IPFields_IPClass
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Public",
|
||||||
|
ipv4: "142.250.71.78",
|
||||||
|
ipv6: "2404:6800:4006:812::200e",
|
||||||
|
expectedClass: proto.IPFields_PUBLIC,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Private",
|
||||||
|
ipv4: "192.168.0.1",
|
||||||
|
ipv6: "fd12:3456:789a:1::1",
|
||||||
|
expectedClass: proto.IPFields_PRIVATE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "LinkLocal",
|
||||||
|
ipv4: "169.254.1.1",
|
||||||
|
ipv6: "fe80::1",
|
||||||
|
expectedClass: proto.IPFields_LINK_LOCAL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Loopback",
|
||||||
|
ipv4: "127.0.0.1",
|
||||||
|
ipv6: "::1",
|
||||||
|
expectedClass: proto.IPFields_LOOPBACK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "IPv4Mapped",
|
||||||
|
ipv4: "1.2.3.4",
|
||||||
|
ipv6: "::ffff:1.2.3.4",
|
||||||
|
expectedClass: proto.IPFields_PUBLIC,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
c := c
|
||||||
|
t.Run(c.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
telemetry, err := newTelemetryStore()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
telemetry.setNetInfo(&tailcfg.NetInfo{
|
||||||
|
GlobalV4: c.ipv4,
|
||||||
|
GlobalV6: c.ipv6,
|
||||||
|
})
|
||||||
|
|
||||||
|
event := telemetry.newEvent()
|
||||||
|
|
||||||
|
v4hash := telemetry.hashAddrorHostname(c.ipv4)
|
||||||
|
require.Equal(t, &proto.Netcheck_NetcheckIP{
|
||||||
|
Hash: v4hash,
|
||||||
|
Fields: &proto.IPFields{
|
||||||
|
Version: 4,
|
||||||
|
Class: c.expectedClass,
|
||||||
|
},
|
||||||
|
}, event.LatestNetcheck.GlobalV4)
|
||||||
|
|
||||||
|
v6hash := telemetry.hashAddrorHostname(c.ipv6)
|
||||||
|
require.Equal(t, &proto.Netcheck_NetcheckIP{
|
||||||
|
Hash: v6hash,
|
||||||
|
Fields: &proto.IPFields{
|
||||||
|
Version: 6,
|
||||||
|
Class: c.expectedClass,
|
||||||
|
},
|
||||||
|
}, event.LatestNetcheck.GlobalV6)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("DerpMapClean", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
telemetry, err := newTelemetryStore()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
derpMap := &tailcfg.DERPMap{
|
||||||
|
Regions: make(map[int]*tailcfg.DERPRegion),
|
||||||
|
}
|
||||||
|
derpMap.Regions[998] = &tailcfg.DERPRegion{
|
||||||
|
RegionID: 998,
|
||||||
|
EmbeddedRelay: true,
|
||||||
|
RegionCode: "zzz",
|
||||||
|
RegionName: "Cool Region",
|
||||||
|
Avoid: true,
|
||||||
|
|
||||||
|
Nodes: []*tailcfg.DERPNode{
|
||||||
|
{
|
||||||
|
Name: "zzz1",
|
||||||
|
RegionID: 998,
|
||||||
|
HostName: "coolderp.com",
|
||||||
|
CertName: "coolderpcert",
|
||||||
|
IPv4: "1.2.3.4",
|
||||||
|
IPv6: "2001:db8::1",
|
||||||
|
STUNTestIP: "5.6.7.8",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
derpMap.Regions[999] = &tailcfg.DERPRegion{
|
||||||
|
RegionID: 999,
|
||||||
|
EmbeddedRelay: true,
|
||||||
|
RegionCode: "zzo",
|
||||||
|
RegionName: "Other Cool Region",
|
||||||
|
Avoid: true,
|
||||||
|
Nodes: []*tailcfg.DERPNode{
|
||||||
|
{
|
||||||
|
Name: "zzo1",
|
||||||
|
HostName: "coolderp.com",
|
||||||
|
CertName: "coolderpcert",
|
||||||
|
IPv4: "1.2.3.4",
|
||||||
|
IPv6: "2001:db8::1",
|
||||||
|
STUNTestIP: "5.6.7.8",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
telemetry.updateDerpMap(derpMap)
|
||||||
|
|
||||||
|
event := telemetry.newEvent()
|
||||||
|
require.Len(t, event.DerpMap.Regions[999].Nodes, 1)
|
||||||
|
node := event.DerpMap.Regions[999].Nodes[0]
|
||||||
|
require.NotContains(t, node.HostName, "coolderp.com")
|
||||||
|
require.NotContains(t, node.Ipv4, "1.2.3.4")
|
||||||
|
require.NotContains(t, node.Ipv6, "2001:db8::1")
|
||||||
|
require.NotContains(t, node.StunTestIp, "5.6.7.8")
|
||||||
|
otherNode := event.DerpMap.Regions[998].Nodes[0]
|
||||||
|
require.Equal(t, otherNode.HostName, node.HostName)
|
||||||
|
require.Equal(t, otherNode.Ipv4, node.Ipv4)
|
||||||
|
require.Equal(t, otherNode.Ipv6, node.Ipv6)
|
||||||
|
require.Equal(t, otherNode.StunTestIp, node.StunTestIp)
|
||||||
|
})
|
||||||
|
}
|
Reference in New Issue
Block a user