Files
tailscale/feature/tailnetlock/tailnetlock.go
T
Simon LawandGitHub 358c975aea cmd/tailscale/jsonoutput: hoist jsonoutput out of cli package (#20591)
Flatten the cmd/tailscale package hierarchy by extracting the
jsonoutput package out of the cmd/tailscale/cli package.

Updates #cleanup

Change-Id: I92f80db75b0328e82f1596b6a42f6f6ef5a94bfa

Signed-off-by: Simon Law <sfllaw@tailscale.com>
2026-07-27 13:41:15 -07:00

55 lines
1.4 KiB
Go

// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause
// package tailnetlock registers the tailnet lock debug C2N handler. In the
// future, all tailnet lock code should move here.
package tailnetlock
import (
"fmt"
"net/http"
"strconv"
"tailscale.com/cmd/tailscale/jsonoutput"
"tailscale.com/feature"
"tailscale.com/feature/buildfeatures"
"tailscale.com/ipn/ipnlocal"
)
func init() {
feature.Register("tailnetlock")
ipnlocal.RegisterC2N("/debug/tka/log", handleC2NDebugTKALog)
}
const defaultC2NLogLimit = 50
const maxC2NLogLimit = 1000
func handleC2NDebugTKALog(b *ipnlocal.LocalBackend, w http.ResponseWriter, r *http.Request) {
if !buildfeatures.HasDebug {
http.Error(w, feature.ErrUnavailable.Error(), http.StatusNotImplemented)
return
}
logf := b.Logger()
logf("c2n: %s %s received", r.Method, r.URL)
limit := defaultC2NLogLimit
limitStr := r.URL.Query().Get("limit")
if limitStr != "" {
if parsed, err := strconv.Atoi(limitStr); err == nil {
limit = min(parsed, maxC2NLogLimit)
}
}
updates, err := b.TailnetLockLog(limit)
if ipnlocal.IsTailnetLockNotActive(err) {
http.Error(w, "tailnet lock not active", http.StatusBadRequest)
return
} else if err != nil {
http.Error(w, fmt.Sprintf("failed to get tailnet lock log: %v", err), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
jsonoutput.PrintTailnetLockLogJSONV1(w, updates)
}