control/controlclient, ipn: add client audit logging (#14950)

updates tailscale/corp#26435

Adds client support for sending audit logs to control via /machine/audit-log.
Specifically implements audit logging for user initiated disconnections.

This will require further work to optimize the peristant storage and exclusion
via build tags for mobile:
tailscale/corp#27011
tailscale/corp#27012

Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
This commit is contained in:
Jonathan Nobels
2025-03-12 10:37:03 -04:00
committed by GitHub
parent 06ae52d309
commit 52710945f5
13 changed files with 1204 additions and 13 deletions

View File

@ -0,0 +1,51 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package controlclient
import (
"errors"
"fmt"
"net/http"
)
// apiResponseError is an error type that can be returned by controlclient
// api requests.
//
// It wraps an underlying error and a flag for clients to query if the
// error is retryable via the Retryable() method.
type apiResponseError struct {
err error
retryable bool
}
// Error implements [error].
func (e *apiResponseError) Error() string {
return e.err.Error()
}
// Retryable reports whether the error is retryable.
func (e *apiResponseError) Retryable() bool {
return e.retryable
}
func (e *apiResponseError) Unwrap() error { return e.err }
var (
errNoNodeKey = &apiResponseError{errors.New("no node key"), true}
errNoNoiseClient = &apiResponseError{errors.New("no noise client"), true}
errHTTPPostFailure = &apiResponseError{errors.New("http failure"), true}
)
func errBadHTTPResponse(code int, msg string) error {
retryable := false
switch code {
case http.StatusTooManyRequests,
http.StatusInternalServerError,
http.StatusBadGateway,
http.StatusServiceUnavailable,
http.StatusGatewayTimeout:
retryable = true
}
return &apiResponseError{fmt.Errorf("http error %d: %s", code, msg), retryable}
}