cmd/tailscale/cli,client,ipn: add appc-routes cli command

Allow the user to access information about routes an app connector has
learned, such as how many routes for each domain.

Fixes tailscale/corp#32624

Signed-off-by: Fran Bull <fran@tailscale.com>
This commit is contained in:
Fran Bull
2025-09-24 15:02:57 -07:00
committed by franbull
parent 976389c0f7
commit 65d6c80695
12 changed files with 201 additions and 5 deletions
+20
View File
@@ -25,6 +25,7 @@ import (
"time"
"golang.org/x/net/dns/dnsmessage"
"tailscale.com/appc"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/clientupdate"
"tailscale.com/envknob"
@@ -73,6 +74,7 @@ var handler = map[string]LocalAPIHandler{
// The other /localapi/v0/NAME handlers are exact matches and contain only NAME
// without a trailing slash:
"alpha-set-device-attrs": (*Handler).serveSetDeviceAttrs, // see tailscale/corp#24690
"appc-route-info": (*Handler).serveGetAppcRouteInfo,
"bugreport": (*Handler).serveBugReport,
"check-ip-forwarding": (*Handler).serveCheckIPForwarding,
"check-prefs": (*Handler).serveCheckPrefs,
@@ -2111,3 +2113,21 @@ func (h *Handler) serveShutdown(w http.ResponseWriter, r *http.Request) {
eventbus.Publish[Shutdown](ec).Publish(Shutdown{})
}
func (h *Handler) serveGetAppcRouteInfo(w http.ResponseWriter, r *http.Request) {
if r.Method != httpm.GET {
http.Error(w, "only GET allowed", http.StatusMethodNotAllowed)
return
}
res, err := h.b.ReadRouteInfo()
if err != nil {
if errors.Is(err, ipn.ErrStateNotExist) {
res = &appc.RouteInfo{}
} else {
WriteErrorJSON(w, err)
return
}
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(res)
}