diff --git a/feature/conn25/api.go b/feature/conn25/api.go index 34a6038ac..4b3953d42 100644 --- a/feature/conn25/api.go +++ b/feature/conn25/api.go @@ -51,6 +51,31 @@ func serveLocalAPIStateGet(h *localapi.Handler, w http.ResponseWriter, r *http.R } } +// serveC2NStateGet serves the C2N endpoint /conn25/state. +// See also [*Conn25.GetActiveState]. +func serveC2NStateGet(b *ipnlocal.LocalBackend, w http.ResponseWriter, r *http.Request) { + // TODO(tailscale/corp#39033): Remove for alpha release. + if !envknob.UseWIPCode() && !testenv.InTest() { + w.WriteHeader(http.StatusNotImplemented) + return + } + + logf := b.Logger() + logf("c2n: GET /conn25/state received") + + ext, ok := ipnlocal.GetExt[*extension](b) + if !ok { + http.Error(w, "miswired", http.StatusInternalServerError) + return + } + state := ext.conn25.GetActiveState() + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(state); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + // GetActiveState returns active state for the client and the connector, // including IP pool usage, address mappings, domains, and active flow counts. func (c *Conn25) GetActiveState() appctype.Conn25ActiveState { diff --git a/feature/conn25/conn25.go b/feature/conn25/conn25.go index 8437a76cc..3ba94e0d4 100644 --- a/feature/conn25/conn25.go +++ b/feature/conn25/conn25.go @@ -86,6 +86,7 @@ func init() { ipnlocal.RegisterPeerAPIHandler("/v0/connector/transit-ip", handleConnectorTransitIP) ipnlocal.HookReplyToDNSQueries.Add(handleHookReplyToDNSQueries) localapi.Register("conn25/state", serveLocalAPIStateGet) + ipnlocal.RegisterC2N("GET /conn25/state", serveC2NStateGet) } func handleConnectorTransitIP(h ipnlocal.PeerAPIHandler, w http.ResponseWriter, r *http.Request) {