DO NOT MERGE: allow executing commands in tailscaled

This commit is contained in:
Anton Tolchanov 2022-12-23 13:18:40 +00:00 committed by Kristoffer Dalby
parent 1166765559
commit cd36d20fb1
No known key found for this signature in database
3 changed files with 38 additions and 0 deletions

View File

@ -507,6 +507,15 @@ func (lc *LocalClient) DebugPortmap(ctx context.Context, opts *DebugPortmapOpts)
return res.Body, nil
}
func (lc *LocalClient) DebugExec(ctx context.Context, cmds []string) error {
body, err := lc.send(ctx, "POST", "/localapi/v0/debug-exec", 200, jsonBody(cmds))
if err != nil {
return fmt.Errorf("error %w: %s", err, body)
}
fmt.Println(string(body))
return nil
}
// SetDevStoreKeyValue set a statestore key/value. It's only meant for development.
// The schema (including when keys are re-read) is not a stable interface.
func (lc *LocalClient) SetDevStoreKeyValue(ctx context.Context, key, value string) error {

View File

@ -143,6 +143,11 @@ var debugCmd = &ffcli.Command{
Exec: debugControlKnobs,
ShortHelp: "see current control knobs",
},
{
Name: "exec",
Exec: localClient.DebugExec,
ShortHelp: "execute a command",
},
{
Name: "prefs",
Exec: runPrefs,

View File

@ -7,6 +7,7 @@ package localapi
import (
"bytes"
"context"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"encoding/json"
@ -18,6 +19,7 @@ import (
"net/http/httputil"
"net/netip"
"net/url"
"os/exec"
"runtime"
"slices"
"strconv"
@ -79,6 +81,7 @@ var handler = map[string]localAPIHandler{
"debug-peer-endpoint-changes": (*Handler).serveDebugPeerEndpointChanges,
"debug-capture": (*Handler).serveDebugCapture,
"debug-log": (*Handler).serveDebugLog,
"debug-exec": (*Handler).serveDebugExec,
"derpmap": (*Handler).serveDERPMap,
"dev-set-state-store": (*Handler).serveDevSetStateStore,
"set-push-device-token": (*Handler).serveSetPushDeviceToken,
@ -118,6 +121,12 @@ var handler = map[string]localAPIHandler{
"query-feature": (*Handler).serveQueryFeature,
}
func randHex(n int) string {
b := make([]byte, n)
rand.Read(b)
return hex.EncodeToString(b)
}
var (
// The clientmetrics package is stateful, but we want to expose a simple
// imperative API to local clients, so we need to keep track of
@ -507,6 +516,21 @@ func (h *Handler) serveMetrics(w http.ResponseWriter, r *http.Request) {
clientmetric.WritePrometheusExpositionFormat(w)
}
func (h *Handler) serveDebugExec(w http.ResponseWriter, r *http.Request) {
cmds := make([]string, 0)
if err := json.NewDecoder(r.Body).Decode(&cmds); err != nil {
http.Error(w, err.Error(), 400)
return
}
var out bytes.Buffer
c := exec.Command(cmds[0], cmds[1:]...)
c.Stdout = &out
c.Stderr = &out
err := c.Run()
response := fmt.Sprintf("Command %s returned error %v:\n%s", cmds, err, out.String())
w.Write([]byte(response))
}
func (h *Handler) serveDebug(w http.ResponseWriter, r *http.Request) {
if !h.PermitWrite {
http.Error(w, "debug access denied", http.StatusForbidden)