mirror of
https://github.com/tailscale/tailscale.git
synced 2026-05-06 04:36:15 +02:00
Add to tailcfg
This commit is contained in:
parent
d16b635023
commit
275345f498
@ -11,7 +11,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
@ -21,8 +20,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"tailscale.com/clientupdate"
|
||||
"tailscale.com/control/controlclient"
|
||||
"tailscale.com/envknob"
|
||||
@ -30,12 +27,9 @@ import (
|
||||
"tailscale.com/net/sockstats"
|
||||
"tailscale.com/posture"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/ipproto"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/netmap"
|
||||
"tailscale.com/types/views"
|
||||
"tailscale.com/util/clientmetric"
|
||||
"tailscale.com/util/goroutines"
|
||||
"tailscale.com/util/httpm"
|
||||
"tailscale.com/util/set"
|
||||
"tailscale.com/util/syspolicy/pkey"
|
||||
"tailscale.com/util/syspolicy/ptype"
|
||||
@ -54,7 +48,7 @@ var c2nHandlers = map[methodAndPath]c2nHandler{
|
||||
req("/debug/metrics"): handleC2NDebugMetrics,
|
||||
req("/debug/component-logging"): handleC2NDebugComponentLogging,
|
||||
req("/debug/logheap"): handleC2NDebugLogHeap,
|
||||
req("POST /debug/netmap"): handleC2NDebugNetMap,
|
||||
req("/debug/netmap"): handleC2NDebugNetMap,
|
||||
|
||||
// PPROF - We only expose a subset of typical pprof endpoints for security.
|
||||
req("/debug/pprof/heap"): handleC2NPprof,
|
||||
@ -161,37 +155,42 @@ func handleC2NLogtailFlush(b *LocalBackend, w http.ResponseWriter, r *http.Reque
|
||||
|
||||
func handleC2NDebugNetMap(b *LocalBackend, w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
b.logf("c2n: POST /debug/netmap received")
|
||||
var body struct {
|
||||
// If set, this MapResponse is used to generate a candidate netmap
|
||||
// to compare against the current one.
|
||||
Candidate *tailcfg.MapResponse `json:"candidate,omitempty"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
if r.Method != httpm.POST && r.Method != httpm.GET {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
resp := struct {
|
||||
// Current netmap, based on the existing map poll + all the deltas.
|
||||
Current *netmap.NetworkMap `json:"current"`
|
||||
|
||||
// A fresh netmap generated based on the MapResponse from the request.
|
||||
Candidate *netmap.NetworkMap `json:"candidate,omitempty"` // optional
|
||||
Diff string
|
||||
}{
|
||||
Current: b.NetMapWithPeers(),
|
||||
b.logf("c2n: %s /debug/netmap received", r.Method)
|
||||
|
||||
cur, err := json.Marshal(b.NetMapWithPeers())
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to marshal current netmap: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if body.Candidate != nil {
|
||||
cand, err := controlclient.NetmapFromMapResponse(ctx, b.pm.CurrentPrefs(), body.Candidate)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to convert candidate MapResponse: %v", err), http.StatusBadRequest)
|
||||
|
||||
resp := &tailcfg.C2NDebugNetmapResponse{Current: cur}
|
||||
|
||||
if r.Method == httpm.POST {
|
||||
var req tailcfg.C2NDebugNetmapRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
resp.Candidate = cand
|
||||
resp.Diff = cmp.Diff(resp.Candidate, resp.Current,
|
||||
cmp.AllowUnexported(netmap.NetworkMap{}),
|
||||
cmpopts.IgnoreUnexported(views.Slice[ipproto.Proto]{}, views.Slice[tailcfg.FilterRule]{}),
|
||||
cmpopts.EquateComparable(key.NodePublic{}, key.MachinePublic{}, ipproto.Proto(0), netip.Prefix{}))
|
||||
|
||||
if req.Candidate != nil {
|
||||
// cand, err := b.ccAuto.DirectForTest().NetmapFromMapResponse(ctx, b.pm.CurrentPrefs(), body.Candidate)
|
||||
cand, err := controlclient.NetmapFromMapResponse(ctx, b.pm.CurrentPrefs(), req.Candidate)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to convert candidate MapResponse: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
candJSON, err := json.Marshal(cand)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to marshal candidate netmap: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
resp.Candidate = candJSON
|
||||
}
|
||||
}
|
||||
writeJSON(w, resp)
|
||||
}
|
||||
|
||||
@ -5,7 +5,10 @@
|
||||
|
||||
package tailcfg
|
||||
|
||||
import "net/netip"
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
// C2NSSHUsernamesRequest is the request for the /ssh/usernames.
|
||||
// A GET request without a request body is equivalent to the zero value of this type.
|
||||
@ -117,3 +120,15 @@ type C2NVIPServicesResponse struct {
|
||||
// changes. This value matches what is reported in latest [Hostinfo.ServicesHash].
|
||||
ServicesHash string
|
||||
}
|
||||
|
||||
type C2NDebugNetmapRequest struct {
|
||||
Candidate *MapResponse `json:"candidate,omitempty"`
|
||||
}
|
||||
|
||||
type C2NDebugNetmapResponse struct {
|
||||
// Current is the current network map (netmap.NetworkMap).
|
||||
Current json.RawMessage `json:"current"`
|
||||
|
||||
// Candidate is a network map produced based on the candidate MapResponse.
|
||||
Candidate json.RawMessage `json:"candidate,omitempty"`
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user