localapi.go 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Package localapi contains the HTTP server handlers for tailscaled's API server.
  4. package localapi
  5. import (
  6. "bytes"
  7. "context"
  8. "crypto/sha256"
  9. "encoding/hex"
  10. "encoding/json"
  11. "errors"
  12. "fmt"
  13. "io"
  14. "net"
  15. "net/http"
  16. "net/http/httputil"
  17. "net/netip"
  18. "net/url"
  19. "runtime"
  20. "slices"
  21. "strconv"
  22. "strings"
  23. "sync"
  24. "time"
  25. "tailscale.com/client/tailscale/apitype"
  26. "tailscale.com/envknob"
  27. "tailscale.com/health"
  28. "tailscale.com/hostinfo"
  29. "tailscale.com/ipn"
  30. "tailscale.com/ipn/ipnlocal"
  31. "tailscale.com/ipn/ipnstate"
  32. "tailscale.com/logtail"
  33. "tailscale.com/net/netmon"
  34. "tailscale.com/net/netutil"
  35. "tailscale.com/net/portmapper"
  36. "tailscale.com/net/tstun"
  37. "tailscale.com/tailcfg"
  38. "tailscale.com/tka"
  39. "tailscale.com/tstime"
  40. "tailscale.com/types/key"
  41. "tailscale.com/types/logger"
  42. "tailscale.com/types/logid"
  43. "tailscale.com/types/ptr"
  44. "tailscale.com/types/tkatype"
  45. "tailscale.com/util/clientmetric"
  46. "tailscale.com/util/httpm"
  47. "tailscale.com/util/mak"
  48. "tailscale.com/util/osdiag"
  49. "tailscale.com/util/rands"
  50. "tailscale.com/version"
  51. )
  52. type localAPIHandler func(*Handler, http.ResponseWriter, *http.Request)
  53. // handler is the set of LocalAPI handlers, keyed by the part of the
  54. // Request.URL.Path after "/localapi/v0/". If the key ends with a trailing slash
  55. // then it's a prefix match.
  56. var handler = map[string]localAPIHandler{
  57. // The prefix match handlers end with a slash:
  58. "cert/": (*Handler).serveCert,
  59. "file-put/": (*Handler).serveFilePut,
  60. "files/": (*Handler).serveFiles,
  61. "profiles/": (*Handler).serveProfiles,
  62. // The other /localapi/v0/NAME handlers are exact matches and contain only NAME
  63. // without a trailing slash:
  64. "bugreport": (*Handler).serveBugReport,
  65. "check-ip-forwarding": (*Handler).serveCheckIPForwarding,
  66. "check-prefs": (*Handler).serveCheckPrefs,
  67. "component-debug-logging": (*Handler).serveComponentDebugLogging,
  68. "debug": (*Handler).serveDebug,
  69. "debug-derp-region": (*Handler).serveDebugDERPRegion,
  70. "debug-packet-filter-matches": (*Handler).serveDebugPacketFilterMatches,
  71. "debug-packet-filter-rules": (*Handler).serveDebugPacketFilterRules,
  72. "debug-portmap": (*Handler).serveDebugPortmap,
  73. "debug-peer-endpoint-changes": (*Handler).serveDebugPeerEndpointChanges,
  74. "debug-capture": (*Handler).serveDebugCapture,
  75. "debug-log": (*Handler).serveDebugLog,
  76. "derpmap": (*Handler).serveDERPMap,
  77. "dev-set-state-store": (*Handler).serveDevSetStateStore,
  78. "set-push-device-token": (*Handler).serveSetPushDeviceToken,
  79. "dial": (*Handler).serveDial,
  80. "file-targets": (*Handler).serveFileTargets,
  81. "goroutines": (*Handler).serveGoroutines,
  82. "id-token": (*Handler).serveIDToken,
  83. "login-interactive": (*Handler).serveLoginInteractive,
  84. "logout": (*Handler).serveLogout,
  85. "logtap": (*Handler).serveLogTap,
  86. "metrics": (*Handler).serveMetrics,
  87. "ping": (*Handler).servePing,
  88. "prefs": (*Handler).servePrefs,
  89. "pprof": (*Handler).servePprof,
  90. "reset-auth": (*Handler).serveResetAuth,
  91. "serve-config": (*Handler).serveServeConfig,
  92. "set-dns": (*Handler).serveSetDNS,
  93. "set-expiry-sooner": (*Handler).serveSetExpirySooner,
  94. "start": (*Handler).serveStart,
  95. "status": (*Handler).serveStatus,
  96. "tka/init": (*Handler).serveTKAInit,
  97. "tka/log": (*Handler).serveTKALog,
  98. "tka/modify": (*Handler).serveTKAModify,
  99. "tka/sign": (*Handler).serveTKASign,
  100. "tka/status": (*Handler).serveTKAStatus,
  101. "tka/disable": (*Handler).serveTKADisable,
  102. "tka/force-local-disable": (*Handler).serveTKALocalDisable,
  103. "tka/affected-sigs": (*Handler).serveTKAAffectedSigs,
  104. "tka/wrap-preauth-key": (*Handler).serveTKAWrapPreauthKey,
  105. "tka/verify-deeplink": (*Handler).serveTKAVerifySigningDeeplink,
  106. "tka/generate-recovery-aum": (*Handler).serveTKAGenerateRecoveryAUM,
  107. "tka/cosign-recovery-aum": (*Handler).serveTKACosignRecoveryAUM,
  108. "tka/submit-recovery-aum": (*Handler).serveTKASubmitRecoveryAUM,
  109. "upload-client-metrics": (*Handler).serveUploadClientMetrics,
  110. "watch-ipn-bus": (*Handler).serveWatchIPNBus,
  111. "whois": (*Handler).serveWhoIs,
  112. "query-feature": (*Handler).serveQueryFeature,
  113. }
  114. var (
  115. // The clientmetrics package is stateful, but we want to expose a simple
  116. // imperative API to local clients, so we need to keep track of
  117. // clientmetric.Metric instances that we've created for them. These need to
  118. // be globals because we end up creating many Handler instances for the
  119. // lifetime of a client.
  120. metricsMu sync.Mutex
  121. metrics = map[string]*clientmetric.Metric{}
  122. )
  123. // NewHandler creates a new LocalAPI HTTP handler. All parameters except netMon
  124. // are required (if non-nil it's used to do faster interface lookups).
  125. func NewHandler(b *ipnlocal.LocalBackend, logf logger.Logf, netMon *netmon.Monitor, logID logid.PublicID) *Handler {
  126. return &Handler{b: b, logf: logf, netMon: netMon, backendLogID: logID, clock: tstime.StdClock{}}
  127. }
  128. type Handler struct {
  129. // RequiredPassword, if non-empty, forces all HTTP
  130. // requests to have HTTP basic auth with this password.
  131. // It's used by the sandboxed macOS sameuserproof GUI auth mechanism.
  132. RequiredPassword string
  133. // PermitRead is whether read-only HTTP handlers are allowed.
  134. PermitRead bool
  135. // PermitWrite is whether mutating HTTP handlers are allowed.
  136. // If PermitWrite is true, everything is allowed.
  137. // It effectively means that the user is root or the admin
  138. // (operator user).
  139. PermitWrite bool
  140. // PermitCert is whether the client is additionally granted
  141. // cert fetching access.
  142. PermitCert bool
  143. b *ipnlocal.LocalBackend
  144. logf logger.Logf
  145. netMon *netmon.Monitor // optional; nil means interfaces will be looked up on-demand
  146. backendLogID logid.PublicID
  147. clock tstime.Clock
  148. }
  149. func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  150. if h.b == nil {
  151. http.Error(w, "server has no local backend", http.StatusInternalServerError)
  152. return
  153. }
  154. if r.Referer() != "" || r.Header.Get("Origin") != "" || !h.validHost(r.Host) {
  155. metricInvalidRequests.Add(1)
  156. http.Error(w, "invalid localapi request", http.StatusForbidden)
  157. return
  158. }
  159. w.Header().Set("Tailscale-Version", version.Long())
  160. w.Header().Set("Tailscale-Cap", strconv.Itoa(int(tailcfg.CurrentCapabilityVersion)))
  161. w.Header().Set("Content-Security-Policy", `default-src 'none'; frame-ancestors 'none'; script-src 'none'; script-src-elem 'none'; script-src-attr 'none'`)
  162. w.Header().Set("X-Frame-Options", "DENY")
  163. w.Header().Set("X-Content-Type-Options", "nosniff")
  164. if h.RequiredPassword != "" {
  165. _, pass, ok := r.BasicAuth()
  166. if !ok {
  167. metricInvalidRequests.Add(1)
  168. http.Error(w, "auth required", http.StatusUnauthorized)
  169. return
  170. }
  171. if pass != h.RequiredPassword {
  172. metricInvalidRequests.Add(1)
  173. http.Error(w, "bad password", http.StatusForbidden)
  174. return
  175. }
  176. }
  177. if fn, ok := handlerForPath(r.URL.Path); ok {
  178. fn(h, w, r)
  179. } else {
  180. http.NotFound(w, r)
  181. }
  182. }
  183. // validLocalHostForTesting allows loopback handlers without RequiredPassword for testing.
  184. var validLocalHostForTesting = false
  185. // validHost reports whether h is a valid Host header value for a LocalAPI request.
  186. func (h *Handler) validHost(hostname string) bool {
  187. // The client code sends a hostname of "local-tailscaled.sock".
  188. switch hostname {
  189. case "", apitype.LocalAPIHost:
  190. return true
  191. }
  192. if !validLocalHostForTesting && h.RequiredPassword == "" {
  193. return false // only allow localhost with basic auth or in tests
  194. }
  195. host, _, err := net.SplitHostPort(hostname)
  196. if err != nil {
  197. return false
  198. }
  199. if host == "localhost" {
  200. return true
  201. }
  202. addr, err := netip.ParseAddr(host)
  203. if err != nil {
  204. return false
  205. }
  206. return addr.IsLoopback()
  207. }
  208. // handlerForPath returns the LocalAPI handler for the provided Request.URI.Path.
  209. // (the path doesn't include any query parameters)
  210. func handlerForPath(urlPath string) (h localAPIHandler, ok bool) {
  211. if urlPath == "/" {
  212. return (*Handler).serveLocalAPIRoot, true
  213. }
  214. suff, ok := strings.CutPrefix(urlPath, "/localapi/v0/")
  215. if !ok {
  216. // Currently all LocalAPI methods start with "/localapi/v0/" to signal
  217. // to people that they're not necessarily stable APIs. In practice we'll
  218. // probably need to keep them pretty stable anyway, but for now treat
  219. // them as an internal implementation detail.
  220. return nil, false
  221. }
  222. if fn, ok := handler[suff]; ok {
  223. // Here we match exact handler suffixes like "status" or ones with a
  224. // slash already in their name, like "tka/status".
  225. return fn, true
  226. }
  227. // Otherwise, it might be a prefix match like "files/*" which we look up
  228. // by the prefix including first trailing slash.
  229. if i := strings.IndexByte(suff, '/'); i != -1 {
  230. suff = suff[:i+1]
  231. if fn, ok := handler[suff]; ok {
  232. return fn, true
  233. }
  234. }
  235. return nil, false
  236. }
  237. func (*Handler) serveLocalAPIRoot(w http.ResponseWriter, r *http.Request) {
  238. io.WriteString(w, "tailscaled\n")
  239. }
  240. // serveIDToken handles requests to get an OIDC ID token.
  241. func (h *Handler) serveIDToken(w http.ResponseWriter, r *http.Request) {
  242. if !h.PermitWrite {
  243. http.Error(w, "id-token access denied", http.StatusForbidden)
  244. return
  245. }
  246. nm := h.b.NetMap()
  247. if nm == nil {
  248. http.Error(w, "no netmap", http.StatusServiceUnavailable)
  249. return
  250. }
  251. aud := strings.TrimSpace(r.FormValue("aud"))
  252. if len(aud) == 0 {
  253. http.Error(w, "no audience requested", http.StatusBadRequest)
  254. return
  255. }
  256. req := &tailcfg.TokenRequest{
  257. CapVersion: tailcfg.CurrentCapabilityVersion,
  258. Audience: aud,
  259. NodeKey: nm.NodeKey,
  260. }
  261. b, err := json.Marshal(req)
  262. if err != nil {
  263. http.Error(w, err.Error(), 500)
  264. return
  265. }
  266. httpReq, err := http.NewRequest("POST", "https://unused/machine/id-token", bytes.NewReader(b))
  267. if err != nil {
  268. http.Error(w, err.Error(), 500)
  269. return
  270. }
  271. resp, err := h.b.DoNoiseRequest(httpReq)
  272. if err != nil {
  273. http.Error(w, err.Error(), 500)
  274. return
  275. }
  276. defer resp.Body.Close()
  277. w.WriteHeader(resp.StatusCode)
  278. if _, err := io.Copy(w, resp.Body); err != nil {
  279. http.Error(w, err.Error(), 500)
  280. return
  281. }
  282. }
  283. func (h *Handler) serveBugReport(w http.ResponseWriter, r *http.Request) {
  284. if !h.PermitRead {
  285. http.Error(w, "bugreport access denied", http.StatusForbidden)
  286. return
  287. }
  288. if r.Method != "POST" {
  289. http.Error(w, "only POST allowed", http.StatusMethodNotAllowed)
  290. return
  291. }
  292. defer h.b.TryFlushLogs() // kick off upload after bugreport's done logging
  293. logMarker := func() string {
  294. return fmt.Sprintf("BUG-%v-%v-%v", h.backendLogID, h.clock.Now().UTC().Format("20060102150405Z"), rands.HexString(16))
  295. }
  296. if envknob.NoLogsNoSupport() {
  297. logMarker = func() string { return "BUG-NO-LOGS-NO-SUPPORT-this-node-has-had-its-logging-disabled" }
  298. }
  299. startMarker := logMarker()
  300. h.logf("user bugreport: %s", startMarker)
  301. if note := r.URL.Query().Get("note"); len(note) > 0 {
  302. h.logf("user bugreport note: %s", note)
  303. }
  304. hi, _ := json.Marshal(hostinfo.New())
  305. h.logf("user bugreport hostinfo: %s", hi)
  306. if err := health.OverallError(); err != nil {
  307. h.logf("user bugreport health: %s", err.Error())
  308. } else {
  309. h.logf("user bugreport health: ok")
  310. }
  311. // Information about the current node from the netmap
  312. if nm := h.b.NetMap(); nm != nil {
  313. if self := nm.SelfNode; self.Valid() {
  314. h.logf("user bugreport node info: nodeid=%q stableid=%q expiry=%q", self.ID(), self.StableID(), self.KeyExpiry().Format(time.RFC3339))
  315. }
  316. h.logf("user bugreport public keys: machine=%q node=%q", nm.MachineKey, nm.NodeKey)
  317. } else {
  318. h.logf("user bugreport netmap: no active netmap")
  319. }
  320. // Print all envknobs; we otherwise only print these on startup, and
  321. // printing them here ensures we don't have to go spelunking through
  322. // logs for them.
  323. envknob.LogCurrent(logger.WithPrefix(h.logf, "user bugreport: "))
  324. // OS-specific details
  325. osdiag.LogSupportInfo(logger.WithPrefix(h.logf, "user bugreport OS: "), osdiag.LogSupportInfoReasonBugReport)
  326. if defBool(r.URL.Query().Get("diagnose"), false) {
  327. h.b.Doctor(r.Context(), logger.WithPrefix(h.logf, "diag: "))
  328. }
  329. w.Header().Set("Content-Type", "text/plain")
  330. fmt.Fprintln(w, startMarker)
  331. // Nothing else to do if we're not in record mode; we wrote the marker
  332. // above, so we can just finish our response now.
  333. if !defBool(r.URL.Query().Get("record"), false) {
  334. return
  335. }
  336. until := h.clock.Now().Add(12 * time.Hour)
  337. var changed map[string]bool
  338. for _, component := range []string{"magicsock"} {
  339. if h.b.GetComponentDebugLogging(component).IsZero() {
  340. if err := h.b.SetComponentDebugLogging(component, until); err != nil {
  341. h.logf("bugreport: error setting component %q logging: %v", component, err)
  342. continue
  343. }
  344. mak.Set(&changed, component, true)
  345. }
  346. }
  347. defer func() {
  348. for component := range changed {
  349. h.b.SetComponentDebugLogging(component, time.Time{})
  350. }
  351. }()
  352. // NOTE(andrew): if we have anything else we want to do while recording
  353. // a bugreport, we can add it here.
  354. // Read from the client; this will also return when the client closes
  355. // the connection.
  356. var buf [1]byte
  357. _, err := r.Body.Read(buf[:])
  358. switch {
  359. case err == nil:
  360. // good
  361. case errors.Is(err, io.EOF):
  362. // good
  363. case errors.Is(err, io.ErrUnexpectedEOF):
  364. // this happens when Ctrl-C'ing the tailscale client; don't
  365. // bother logging an error
  366. default:
  367. // Log but continue anyway.
  368. h.logf("user bugreport: error reading body: %v", err)
  369. }
  370. // Generate another log marker and return it to the client.
  371. endMarker := logMarker()
  372. h.logf("user bugreport end: %s", endMarker)
  373. fmt.Fprintln(w, endMarker)
  374. }
  375. func (h *Handler) serveWhoIs(w http.ResponseWriter, r *http.Request) {
  376. if !h.PermitRead {
  377. http.Error(w, "whois access denied", http.StatusForbidden)
  378. return
  379. }
  380. b := h.b
  381. var ipp netip.AddrPort
  382. if v := r.FormValue("addr"); v != "" {
  383. var err error
  384. ipp, err = netip.ParseAddrPort(v)
  385. if err != nil {
  386. http.Error(w, "invalid 'addr' parameter", 400)
  387. return
  388. }
  389. } else {
  390. http.Error(w, "missing 'addr' parameter", 400)
  391. return
  392. }
  393. n, u, ok := b.WhoIs(ipp)
  394. if !ok {
  395. http.Error(w, "no match for IP:port", 404)
  396. return
  397. }
  398. res := &apitype.WhoIsResponse{
  399. Node: n.AsStruct(), // always non-nil per WhoIsResponse contract
  400. UserProfile: &u, // always non-nil per WhoIsResponse contract
  401. CapMap: b.PeerCaps(ipp.Addr()),
  402. }
  403. j, err := json.MarshalIndent(res, "", "\t")
  404. if err != nil {
  405. http.Error(w, "JSON encoding error", 500)
  406. return
  407. }
  408. w.Header().Set("Content-Type", "application/json")
  409. w.Write(j)
  410. }
  411. func (h *Handler) serveGoroutines(w http.ResponseWriter, r *http.Request) {
  412. // Require write access out of paranoia that the goroutine dump
  413. // (at least its arguments) might contain something sensitive.
  414. if !h.PermitWrite {
  415. http.Error(w, "goroutine dump access denied", http.StatusForbidden)
  416. return
  417. }
  418. buf := make([]byte, 2<<20)
  419. buf = buf[:runtime.Stack(buf, true)]
  420. w.Header().Set("Content-Type", "text/plain")
  421. w.Write(buf)
  422. }
  423. // serveLogTap taps into the tailscaled/logtail server output and streams
  424. // it to the client.
  425. func (h *Handler) serveLogTap(w http.ResponseWriter, r *http.Request) {
  426. ctx := r.Context()
  427. // Require write access (~root) as the logs could contain something
  428. // sensitive.
  429. if !h.PermitWrite {
  430. http.Error(w, "logtap access denied", http.StatusForbidden)
  431. return
  432. }
  433. if r.Method != "GET" {
  434. http.Error(w, "GET required", http.StatusMethodNotAllowed)
  435. return
  436. }
  437. f, ok := w.(http.Flusher)
  438. if !ok {
  439. http.Error(w, "streaming unsupported", http.StatusInternalServerError)
  440. return
  441. }
  442. io.WriteString(w, `{"text":"[logtap connected]\n"}`+"\n")
  443. f.Flush()
  444. msgc := make(chan string, 16)
  445. unreg := logtail.RegisterLogTap(msgc)
  446. defer unreg()
  447. for {
  448. select {
  449. case <-ctx.Done():
  450. return
  451. case msg := <-msgc:
  452. io.WriteString(w, msg)
  453. f.Flush()
  454. }
  455. }
  456. }
  457. func (h *Handler) serveMetrics(w http.ResponseWriter, r *http.Request) {
  458. // Require write access out of paranoia that the metrics
  459. // might contain something sensitive.
  460. if !h.PermitWrite {
  461. http.Error(w, "metric access denied", http.StatusForbidden)
  462. return
  463. }
  464. w.Header().Set("Content-Type", "text/plain")
  465. clientmetric.WritePrometheusExpositionFormat(w)
  466. }
  467. func (h *Handler) serveDebug(w http.ResponseWriter, r *http.Request) {
  468. if !h.PermitWrite {
  469. http.Error(w, "debug access denied", http.StatusForbidden)
  470. return
  471. }
  472. if r.Method != "POST" {
  473. http.Error(w, "POST required", http.StatusMethodNotAllowed)
  474. return
  475. }
  476. // The action is normally in a POST form parameter, but
  477. // some actions (like "notify") want a full JSON body, so
  478. // permit some to have their action in a header.
  479. var action string
  480. switch v := r.Header.Get("Debug-Action"); v {
  481. case "notify":
  482. action = v
  483. default:
  484. action = r.FormValue("action")
  485. }
  486. var err error
  487. switch action {
  488. case "rebind":
  489. err = h.b.DebugRebind()
  490. case "restun":
  491. err = h.b.DebugReSTUN()
  492. case "enginestatus":
  493. // serveRequestEngineStatus kicks off a call to RequestEngineStatus (via
  494. // LocalBackend => UserspaceEngine => LocalBackend =>
  495. // ipn.Notify{Engine}).
  496. //
  497. // This is a temporary (2022-11-25) measure for the Windows client's
  498. // move to the LocalAPI HTTP interface. It was polling this over the IPN
  499. // bus before every 2 seconds which is wasteful. We should add a bit to
  500. // WatchIPNMask instead to let an IPN bus watcher say that it's
  501. // interested in that info and then only send it on demand, not via
  502. // polling. But for now we keep this interface because that's what the
  503. // client already did. A future change will remove this, so don't depend
  504. // on it.
  505. h.b.RequestEngineStatus()
  506. case "notify":
  507. var n ipn.Notify
  508. err = json.NewDecoder(r.Body).Decode(&n)
  509. if err != nil {
  510. break
  511. }
  512. h.b.DebugNotify(n)
  513. case "break-tcp-conns":
  514. err = h.b.DebugBreakTCPConns()
  515. case "break-derp-conns":
  516. err = h.b.DebugBreakDERPConns()
  517. case "control-knobs":
  518. k := h.b.ControlKnobs()
  519. w.Header().Set("Content-Type", "application/json")
  520. err = json.NewEncoder(w).Encode(k.AsDebugJSON())
  521. if err == nil {
  522. return
  523. }
  524. case "":
  525. err = fmt.Errorf("missing parameter 'action'")
  526. default:
  527. err = fmt.Errorf("unknown action %q", action)
  528. }
  529. if err != nil {
  530. http.Error(w, err.Error(), 400)
  531. return
  532. }
  533. w.Header().Set("Content-Type", "text/plain")
  534. io.WriteString(w, "done\n")
  535. }
  536. func (h *Handler) serveDevSetStateStore(w http.ResponseWriter, r *http.Request) {
  537. if !h.PermitWrite {
  538. http.Error(w, "debug access denied", http.StatusForbidden)
  539. return
  540. }
  541. if r.Method != "POST" {
  542. http.Error(w, "POST required", http.StatusMethodNotAllowed)
  543. return
  544. }
  545. if err := h.b.SetDevStateStore(r.FormValue("key"), r.FormValue("value")); err != nil {
  546. http.Error(w, err.Error(), 500)
  547. return
  548. }
  549. w.Header().Set("Content-Type", "text/plain")
  550. io.WriteString(w, "done\n")
  551. }
  552. func (h *Handler) serveDebugPacketFilterRules(w http.ResponseWriter, r *http.Request) {
  553. if !h.PermitWrite {
  554. http.Error(w, "debug access denied", http.StatusForbidden)
  555. return
  556. }
  557. nm := h.b.NetMap()
  558. if nm == nil {
  559. http.Error(w, "no netmap", http.StatusNotFound)
  560. return
  561. }
  562. w.Header().Set("Content-Type", "application/json")
  563. enc := json.NewEncoder(w)
  564. enc.SetIndent("", "\t")
  565. enc.Encode(nm.PacketFilterRules)
  566. }
  567. func (h *Handler) serveDebugPacketFilterMatches(w http.ResponseWriter, r *http.Request) {
  568. if !h.PermitWrite {
  569. http.Error(w, "debug access denied", http.StatusForbidden)
  570. return
  571. }
  572. nm := h.b.NetMap()
  573. if nm == nil {
  574. http.Error(w, "no netmap", http.StatusNotFound)
  575. return
  576. }
  577. w.Header().Set("Content-Type", "application/json")
  578. enc := json.NewEncoder(w)
  579. enc.SetIndent("", "\t")
  580. enc.Encode(nm.PacketFilter)
  581. }
  582. func (h *Handler) serveDebugPortmap(w http.ResponseWriter, r *http.Request) {
  583. if !h.PermitWrite {
  584. http.Error(w, "debug access denied", http.StatusForbidden)
  585. return
  586. }
  587. w.Header().Set("Content-Type", "text/plain")
  588. dur, err := time.ParseDuration(r.FormValue("duration"))
  589. if err != nil {
  590. http.Error(w, err.Error(), http.StatusBadRequest)
  591. return
  592. }
  593. gwSelf := r.FormValue("gateway_and_self")
  594. // Update portmapper debug flags
  595. debugKnobs := &portmapper.DebugKnobs{VerboseLogs: true}
  596. switch r.FormValue("type") {
  597. case "":
  598. case "pmp":
  599. debugKnobs.DisablePCP = true
  600. debugKnobs.DisableUPnP = true
  601. case "pcp":
  602. debugKnobs.DisablePMP = true
  603. debugKnobs.DisableUPnP = true
  604. case "upnp":
  605. debugKnobs.DisablePCP = true
  606. debugKnobs.DisablePMP = true
  607. default:
  608. http.Error(w, "unknown portmap debug type", http.StatusBadRequest)
  609. return
  610. }
  611. if defBool(r.FormValue("log_http"), false) {
  612. debugKnobs.LogHTTP = true
  613. }
  614. var (
  615. logLock sync.Mutex
  616. handlerDone bool
  617. )
  618. logf := func(format string, args ...any) {
  619. if !strings.HasSuffix(format, "\n") {
  620. format = format + "\n"
  621. }
  622. logLock.Lock()
  623. defer logLock.Unlock()
  624. // The portmapper can call this log function after the HTTP
  625. // handler returns, which is not allowed and can cause a panic.
  626. // If this happens, ignore the log lines since this typically
  627. // occurs due to a client disconnect.
  628. if handlerDone {
  629. return
  630. }
  631. // Write and flush each line to the client so that output is streamed
  632. fmt.Fprintf(w, format, args...)
  633. if f, ok := w.(http.Flusher); ok {
  634. f.Flush()
  635. }
  636. }
  637. defer func() {
  638. logLock.Lock()
  639. handlerDone = true
  640. logLock.Unlock()
  641. }()
  642. ctx, cancel := context.WithTimeout(r.Context(), dur)
  643. defer cancel()
  644. done := make(chan bool, 1)
  645. var c *portmapper.Client
  646. c = portmapper.NewClient(logger.WithPrefix(logf, "portmapper: "), h.netMon, debugKnobs, h.b.ControlKnobs(), func() {
  647. logf("portmapping changed.")
  648. logf("have mapping: %v", c.HaveMapping())
  649. if ext, ok := c.GetCachedMappingOrStartCreatingOne(); ok {
  650. logf("cb: mapping: %v", ext)
  651. select {
  652. case done <- true:
  653. default:
  654. }
  655. return
  656. }
  657. logf("cb: no mapping")
  658. })
  659. defer c.Close()
  660. netMon, err := netmon.New(logger.WithPrefix(logf, "monitor: "))
  661. if err != nil {
  662. logf("error creating monitor: %v", err)
  663. return
  664. }
  665. gatewayAndSelfIP := func() (gw, self netip.Addr, ok bool) {
  666. if a, b, ok := strings.Cut(gwSelf, "/"); ok {
  667. gw = netip.MustParseAddr(a)
  668. self = netip.MustParseAddr(b)
  669. return gw, self, true
  670. }
  671. return netMon.GatewayAndSelfIP()
  672. }
  673. c.SetGatewayLookupFunc(gatewayAndSelfIP)
  674. gw, selfIP, ok := gatewayAndSelfIP()
  675. if !ok {
  676. logf("no gateway or self IP; %v", netMon.InterfaceState())
  677. return
  678. }
  679. logf("gw=%v; self=%v", gw, selfIP)
  680. uc, err := net.ListenPacket("udp", "0.0.0.0:0")
  681. if err != nil {
  682. return
  683. }
  684. defer uc.Close()
  685. c.SetLocalPort(uint16(uc.LocalAddr().(*net.UDPAddr).Port))
  686. res, err := c.Probe(ctx)
  687. if err != nil {
  688. logf("error in Probe: %v", err)
  689. return
  690. }
  691. logf("Probe: %+v", res)
  692. if !res.PCP && !res.PMP && !res.UPnP {
  693. logf("no portmapping services available")
  694. return
  695. }
  696. if ext, ok := c.GetCachedMappingOrStartCreatingOne(); ok {
  697. logf("mapping: %v", ext)
  698. } else {
  699. logf("no mapping")
  700. }
  701. select {
  702. case <-done:
  703. case <-ctx.Done():
  704. if r.Context().Err() == nil {
  705. logf("serveDebugPortmap: context done: %v", ctx.Err())
  706. } else {
  707. h.logf("serveDebugPortmap: context done: %v", ctx.Err())
  708. }
  709. }
  710. }
  711. func (h *Handler) serveComponentDebugLogging(w http.ResponseWriter, r *http.Request) {
  712. if !h.PermitWrite {
  713. http.Error(w, "debug access denied", http.StatusForbidden)
  714. return
  715. }
  716. component := r.FormValue("component")
  717. secs, _ := strconv.Atoi(r.FormValue("secs"))
  718. err := h.b.SetComponentDebugLogging(component, h.clock.Now().Add(time.Duration(secs)*time.Second))
  719. var res struct {
  720. Error string
  721. }
  722. if err != nil {
  723. res.Error = err.Error()
  724. }
  725. w.Header().Set("Content-Type", "application/json")
  726. json.NewEncoder(w).Encode(res)
  727. }
  728. // servePprofFunc is the implementation of Handler.servePprof, after auth,
  729. // for platforms where we want to link it in.
  730. var servePprofFunc func(http.ResponseWriter, *http.Request)
  731. func (h *Handler) servePprof(w http.ResponseWriter, r *http.Request) {
  732. // Require write access out of paranoia that the profile dump
  733. // might contain something sensitive.
  734. if !h.PermitWrite {
  735. http.Error(w, "profile access denied", http.StatusForbidden)
  736. return
  737. }
  738. if servePprofFunc == nil {
  739. http.Error(w, "not implemented on this platform", http.StatusServiceUnavailable)
  740. return
  741. }
  742. servePprofFunc(w, r)
  743. }
  744. func (h *Handler) serveResetAuth(w http.ResponseWriter, r *http.Request) {
  745. if !h.PermitWrite {
  746. http.Error(w, "reset-auth modify access denied", http.StatusForbidden)
  747. return
  748. }
  749. if r.Method != httpm.POST {
  750. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  751. return
  752. }
  753. if err := h.b.ResetAuth(); err != nil {
  754. http.Error(w, "reset-auth failed: "+err.Error(), http.StatusInternalServerError)
  755. return
  756. }
  757. w.WriteHeader(http.StatusNoContent)
  758. }
  759. func (h *Handler) serveServeConfig(w http.ResponseWriter, r *http.Request) {
  760. switch r.Method {
  761. case "GET":
  762. if !h.PermitRead {
  763. http.Error(w, "serve config denied", http.StatusForbidden)
  764. return
  765. }
  766. config := h.b.ServeConfig()
  767. bts, err := json.Marshal(config)
  768. if err != nil {
  769. http.Error(w, "error encoding config: "+err.Error(), http.StatusInternalServerError)
  770. return
  771. }
  772. sum := sha256.Sum256(bts)
  773. etag := hex.EncodeToString(sum[:])
  774. w.Header().Set("Etag", etag)
  775. w.Header().Set("Content-Type", "application/json")
  776. w.Write(bts)
  777. case "POST":
  778. if !h.PermitWrite {
  779. http.Error(w, "serve config denied", http.StatusForbidden)
  780. return
  781. }
  782. configIn := new(ipn.ServeConfig)
  783. if err := json.NewDecoder(r.Body).Decode(configIn); err != nil {
  784. writeErrorJSON(w, fmt.Errorf("decoding config: %w", err))
  785. return
  786. }
  787. etag := r.Header.Get("If-Match")
  788. if err := h.b.SetServeConfig(configIn, etag); err != nil {
  789. if errors.Is(err, ipnlocal.ErrETagMismatch) {
  790. http.Error(w, err.Error(), http.StatusPreconditionFailed)
  791. return
  792. }
  793. writeErrorJSON(w, fmt.Errorf("updating config: %w", err))
  794. return
  795. }
  796. w.WriteHeader(http.StatusOK)
  797. default:
  798. http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
  799. }
  800. }
  801. func (h *Handler) serveCheckIPForwarding(w http.ResponseWriter, r *http.Request) {
  802. if !h.PermitRead {
  803. http.Error(w, "IP forwarding check access denied", http.StatusForbidden)
  804. return
  805. }
  806. var warning string
  807. if err := h.b.CheckIPForwarding(); err != nil {
  808. warning = err.Error()
  809. }
  810. w.Header().Set("Content-Type", "application/json")
  811. json.NewEncoder(w).Encode(struct {
  812. Warning string
  813. }{
  814. Warning: warning,
  815. })
  816. }
  817. func (h *Handler) serveStatus(w http.ResponseWriter, r *http.Request) {
  818. if !h.PermitRead {
  819. http.Error(w, "status access denied", http.StatusForbidden)
  820. return
  821. }
  822. w.Header().Set("Content-Type", "application/json")
  823. var st *ipnstate.Status
  824. if defBool(r.FormValue("peers"), true) {
  825. st = h.b.Status()
  826. } else {
  827. st = h.b.StatusWithoutPeers()
  828. }
  829. e := json.NewEncoder(w)
  830. e.SetIndent("", "\t")
  831. e.Encode(st)
  832. }
  833. func (h *Handler) serveDebugPeerEndpointChanges(w http.ResponseWriter, r *http.Request) {
  834. if !h.PermitRead {
  835. http.Error(w, "status access denied", http.StatusForbidden)
  836. return
  837. }
  838. ipStr := r.FormValue("ip")
  839. if ipStr == "" {
  840. http.Error(w, "missing 'ip' parameter", 400)
  841. return
  842. }
  843. ip, err := netip.ParseAddr(ipStr)
  844. if err != nil {
  845. http.Error(w, "invalid IP", 400)
  846. return
  847. }
  848. w.Header().Set("Content-Type", "application/json")
  849. chs, err := h.b.GetPeerEndpointChanges(r.Context(), ip)
  850. if err != nil {
  851. http.Error(w, err.Error(), 500)
  852. return
  853. }
  854. e := json.NewEncoder(w)
  855. e.SetIndent("", "\t")
  856. e.Encode(chs)
  857. }
  858. // InUseOtherUserIPNStream reports whether r is a request for the watch-ipn-bus
  859. // handler. If so, it writes an ipn.Notify InUseOtherUser message to the user
  860. // and returns true. Otherwise it returns false, in which case it doesn't write
  861. // to w.
  862. //
  863. // Unlike the regular watch-ipn-bus handler, this one doesn't block. The caller
  864. // (in ipnserver.Server) provides the blocking until the connection is no longer
  865. // in use.
  866. func InUseOtherUserIPNStream(w http.ResponseWriter, r *http.Request, err error) (handled bool) {
  867. if r.Method != "GET" || r.URL.Path != "/localapi/v0/watch-ipn-bus" {
  868. return false
  869. }
  870. js, err := json.Marshal(&ipn.Notify{
  871. Version: version.Long(),
  872. State: ptr.To(ipn.InUseOtherUser),
  873. ErrMessage: ptr.To(err.Error()),
  874. })
  875. if err != nil {
  876. return false
  877. }
  878. js = append(js, '\n')
  879. w.Header().Set("Content-Type", "application/json")
  880. w.Write(js)
  881. return true
  882. }
  883. func (h *Handler) serveWatchIPNBus(w http.ResponseWriter, r *http.Request) {
  884. if !h.PermitRead {
  885. http.Error(w, "watch ipn bus access denied", http.StatusForbidden)
  886. return
  887. }
  888. f, ok := w.(http.Flusher)
  889. if !ok {
  890. http.Error(w, "not a flusher", http.StatusInternalServerError)
  891. return
  892. }
  893. w.Header().Set("Content-Type", "application/json")
  894. var mask ipn.NotifyWatchOpt
  895. if s := r.FormValue("mask"); s != "" {
  896. v, err := strconv.ParseUint(s, 10, 64)
  897. if err != nil {
  898. http.Error(w, "bad mask", http.StatusBadRequest)
  899. return
  900. }
  901. mask = ipn.NotifyWatchOpt(v)
  902. }
  903. ctx := r.Context()
  904. h.b.WatchNotifications(ctx, mask, f.Flush, func(roNotify *ipn.Notify) (keepGoing bool) {
  905. js, err := json.Marshal(roNotify)
  906. if err != nil {
  907. h.logf("json.Marshal: %v", err)
  908. return false
  909. }
  910. if _, err := fmt.Fprintf(w, "%s\n", js); err != nil {
  911. return false
  912. }
  913. f.Flush()
  914. return true
  915. })
  916. }
  917. func (h *Handler) serveLoginInteractive(w http.ResponseWriter, r *http.Request) {
  918. if !h.PermitWrite {
  919. http.Error(w, "login access denied", http.StatusForbidden)
  920. return
  921. }
  922. if r.Method != "POST" {
  923. http.Error(w, "want POST", 400)
  924. return
  925. }
  926. h.b.StartLoginInteractive()
  927. w.WriteHeader(http.StatusNoContent)
  928. return
  929. }
  930. func (h *Handler) serveStart(w http.ResponseWriter, r *http.Request) {
  931. if !h.PermitWrite {
  932. http.Error(w, "access denied", http.StatusForbidden)
  933. return
  934. }
  935. if r.Method != "POST" {
  936. http.Error(w, "want POST", 400)
  937. return
  938. }
  939. var o ipn.Options
  940. if err := json.NewDecoder(r.Body).Decode(&o); err != nil {
  941. http.Error(w, err.Error(), http.StatusBadRequest)
  942. return
  943. }
  944. err := h.b.Start(o)
  945. if err != nil {
  946. // TODO(bradfitz): map error to a good HTTP error
  947. http.Error(w, err.Error(), http.StatusInternalServerError)
  948. return
  949. }
  950. w.WriteHeader(http.StatusNoContent)
  951. }
  952. func (h *Handler) serveLogout(w http.ResponseWriter, r *http.Request) {
  953. if !h.PermitWrite {
  954. http.Error(w, "logout access denied", http.StatusForbidden)
  955. return
  956. }
  957. if r.Method != "POST" {
  958. http.Error(w, "want POST", 400)
  959. return
  960. }
  961. err := h.b.Logout(r.Context())
  962. if err == nil {
  963. w.WriteHeader(http.StatusNoContent)
  964. return
  965. }
  966. http.Error(w, err.Error(), 500)
  967. }
  968. func (h *Handler) servePrefs(w http.ResponseWriter, r *http.Request) {
  969. if !h.PermitRead {
  970. http.Error(w, "prefs access denied", http.StatusForbidden)
  971. return
  972. }
  973. var prefs ipn.PrefsView
  974. switch r.Method {
  975. case "PATCH":
  976. if !h.PermitWrite {
  977. http.Error(w, "prefs write access denied", http.StatusForbidden)
  978. return
  979. }
  980. mp := new(ipn.MaskedPrefs)
  981. if err := json.NewDecoder(r.Body).Decode(mp); err != nil {
  982. http.Error(w, err.Error(), 400)
  983. return
  984. }
  985. var err error
  986. prefs, err = h.b.EditPrefs(mp)
  987. if err != nil {
  988. w.Header().Set("Content-Type", "application/json")
  989. w.WriteHeader(http.StatusBadRequest)
  990. json.NewEncoder(w).Encode(resJSON{Error: err.Error()})
  991. return
  992. }
  993. case "GET", "HEAD":
  994. prefs = h.b.Prefs()
  995. default:
  996. http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
  997. return
  998. }
  999. w.Header().Set("Content-Type", "application/json")
  1000. e := json.NewEncoder(w)
  1001. e.SetIndent("", "\t")
  1002. e.Encode(prefs)
  1003. }
  1004. type resJSON struct {
  1005. Error string `json:",omitempty"`
  1006. }
  1007. func (h *Handler) serveCheckPrefs(w http.ResponseWriter, r *http.Request) {
  1008. if !h.PermitWrite {
  1009. http.Error(w, "checkprefs access denied", http.StatusForbidden)
  1010. return
  1011. }
  1012. if r.Method != "POST" {
  1013. http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
  1014. return
  1015. }
  1016. p := new(ipn.Prefs)
  1017. if err := json.NewDecoder(r.Body).Decode(p); err != nil {
  1018. http.Error(w, "invalid JSON body", 400)
  1019. return
  1020. }
  1021. err := h.b.CheckPrefs(p)
  1022. var res resJSON
  1023. if err != nil {
  1024. res.Error = err.Error()
  1025. }
  1026. w.Header().Set("Content-Type", "application/json")
  1027. json.NewEncoder(w).Encode(res)
  1028. }
  1029. func (h *Handler) serveFiles(w http.ResponseWriter, r *http.Request) {
  1030. if !h.PermitWrite {
  1031. http.Error(w, "file access denied", http.StatusForbidden)
  1032. return
  1033. }
  1034. suffix, ok := strings.CutPrefix(r.URL.EscapedPath(), "/localapi/v0/files/")
  1035. if !ok {
  1036. http.Error(w, "misconfigured", http.StatusInternalServerError)
  1037. return
  1038. }
  1039. if suffix == "" {
  1040. if r.Method != "GET" {
  1041. http.Error(w, "want GET to list files", 400)
  1042. return
  1043. }
  1044. ctx := r.Context()
  1045. if s := r.FormValue("waitsec"); s != "" && s != "0" {
  1046. d, err := strconv.Atoi(s)
  1047. if err != nil {
  1048. http.Error(w, "invalid waitsec", http.StatusBadRequest)
  1049. return
  1050. }
  1051. deadline := time.Now().Add(time.Duration(d) * time.Second)
  1052. var cancel context.CancelFunc
  1053. ctx, cancel = context.WithDeadline(ctx, deadline)
  1054. defer cancel()
  1055. }
  1056. wfs, err := h.b.AwaitWaitingFiles(ctx)
  1057. if err != nil && ctx.Err() == nil {
  1058. http.Error(w, err.Error(), 500)
  1059. return
  1060. }
  1061. w.Header().Set("Content-Type", "application/json")
  1062. json.NewEncoder(w).Encode(wfs)
  1063. return
  1064. }
  1065. name, err := url.PathUnescape(suffix)
  1066. if err != nil {
  1067. http.Error(w, "bad filename", 400)
  1068. return
  1069. }
  1070. if r.Method == "DELETE" {
  1071. if err := h.b.DeleteFile(name); err != nil {
  1072. http.Error(w, err.Error(), 500)
  1073. return
  1074. }
  1075. w.WriteHeader(http.StatusNoContent)
  1076. return
  1077. }
  1078. rc, size, err := h.b.OpenFile(name)
  1079. if err != nil {
  1080. http.Error(w, err.Error(), 500)
  1081. return
  1082. }
  1083. defer rc.Close()
  1084. w.Header().Set("Content-Length", fmt.Sprint(size))
  1085. w.Header().Set("Content-Type", "application/octet-stream")
  1086. io.Copy(w, rc)
  1087. }
  1088. func writeErrorJSON(w http.ResponseWriter, err error) {
  1089. if err == nil {
  1090. err = errors.New("unexpected nil error")
  1091. }
  1092. w.Header().Set("Content-Type", "application/json")
  1093. w.WriteHeader(500)
  1094. type E struct {
  1095. Error string `json:"error"`
  1096. }
  1097. json.NewEncoder(w).Encode(E{err.Error()})
  1098. }
  1099. func (h *Handler) serveFileTargets(w http.ResponseWriter, r *http.Request) {
  1100. if !h.PermitRead {
  1101. http.Error(w, "access denied", http.StatusForbidden)
  1102. return
  1103. }
  1104. if r.Method != "GET" {
  1105. http.Error(w, "want GET to list targets", 400)
  1106. return
  1107. }
  1108. fts, err := h.b.FileTargets()
  1109. if err != nil {
  1110. writeErrorJSON(w, err)
  1111. return
  1112. }
  1113. mak.NonNilSliceForJSON(&fts)
  1114. w.Header().Set("Content-Type", "application/json")
  1115. json.NewEncoder(w).Encode(fts)
  1116. }
  1117. // serveFilePut sends a file to another node.
  1118. //
  1119. // It's sometimes possible for clients to do this themselves, without
  1120. // tailscaled, except in the case of tailscaled running in
  1121. // userspace-networking ("netstack") mode, in which case tailscaled
  1122. // needs to a do a netstack dial out.
  1123. //
  1124. // Instead, the CLI also goes through tailscaled so it doesn't need to be
  1125. // aware of the network mode in use.
  1126. //
  1127. // macOS/iOS have always used this localapi method to simplify the GUI
  1128. // clients.
  1129. //
  1130. // The Windows client currently (2021-11-30) uses the peerapi (/v0/put/)
  1131. // directly, as the Windows GUI always runs in tun mode anyway.
  1132. //
  1133. // URL format:
  1134. //
  1135. // - PUT /localapi/v0/file-put/:stableID/:escaped-filename
  1136. func (h *Handler) serveFilePut(w http.ResponseWriter, r *http.Request) {
  1137. metricFilePutCalls.Add(1)
  1138. if !h.PermitWrite {
  1139. http.Error(w, "file access denied", http.StatusForbidden)
  1140. return
  1141. }
  1142. if r.Method != "PUT" {
  1143. http.Error(w, "want PUT to put file", 400)
  1144. return
  1145. }
  1146. fts, err := h.b.FileTargets()
  1147. if err != nil {
  1148. http.Error(w, err.Error(), 500)
  1149. return
  1150. }
  1151. upath, ok := strings.CutPrefix(r.URL.EscapedPath(), "/localapi/v0/file-put/")
  1152. if !ok {
  1153. http.Error(w, "misconfigured", http.StatusInternalServerError)
  1154. return
  1155. }
  1156. stableIDStr, filenameEscaped, ok := strings.Cut(upath, "/")
  1157. if !ok {
  1158. http.Error(w, "bogus URL", 400)
  1159. return
  1160. }
  1161. stableID := tailcfg.StableNodeID(stableIDStr)
  1162. var ft *apitype.FileTarget
  1163. for _, x := range fts {
  1164. if x.Node.StableID == stableID {
  1165. ft = x
  1166. break
  1167. }
  1168. }
  1169. if ft == nil {
  1170. http.Error(w, "node not found", 404)
  1171. return
  1172. }
  1173. dstURL, err := url.Parse(ft.PeerAPIURL)
  1174. if err != nil {
  1175. http.Error(w, "bogus peer URL", 500)
  1176. return
  1177. }
  1178. outReq, err := http.NewRequestWithContext(r.Context(), "PUT", "http://peer/v0/put/"+filenameEscaped, r.Body)
  1179. if err != nil {
  1180. http.Error(w, "bogus outreq", 500)
  1181. return
  1182. }
  1183. outReq.ContentLength = r.ContentLength
  1184. rp := httputil.NewSingleHostReverseProxy(dstURL)
  1185. rp.Transport = h.b.Dialer().PeerAPITransport()
  1186. rp.ServeHTTP(w, outReq)
  1187. }
  1188. func (h *Handler) serveSetDNS(w http.ResponseWriter, r *http.Request) {
  1189. if !h.PermitWrite {
  1190. http.Error(w, "access denied", http.StatusForbidden)
  1191. return
  1192. }
  1193. if r.Method != "POST" {
  1194. http.Error(w, "want POST", 400)
  1195. return
  1196. }
  1197. ctx := r.Context()
  1198. err := h.b.SetDNS(ctx, r.FormValue("name"), r.FormValue("value"))
  1199. if err != nil {
  1200. writeErrorJSON(w, err)
  1201. return
  1202. }
  1203. w.Header().Set("Content-Type", "application/json")
  1204. json.NewEncoder(w).Encode(struct{}{})
  1205. }
  1206. func (h *Handler) serveDERPMap(w http.ResponseWriter, r *http.Request) {
  1207. if r.Method != "GET" {
  1208. http.Error(w, "want GET", 400)
  1209. return
  1210. }
  1211. w.Header().Set("Content-Type", "application/json")
  1212. e := json.NewEncoder(w)
  1213. e.SetIndent("", "\t")
  1214. e.Encode(h.b.DERPMap())
  1215. }
  1216. // serveSetExpirySooner sets the expiry date on the current machine, specified
  1217. // by an `expiry` unix timestamp as POST or query param.
  1218. func (h *Handler) serveSetExpirySooner(w http.ResponseWriter, r *http.Request) {
  1219. if !h.PermitWrite {
  1220. http.Error(w, "access denied", http.StatusForbidden)
  1221. return
  1222. }
  1223. if r.Method != "POST" {
  1224. http.Error(w, "POST required", http.StatusMethodNotAllowed)
  1225. return
  1226. }
  1227. var expiryTime time.Time
  1228. if v := r.FormValue("expiry"); v != "" {
  1229. expiryInt, err := strconv.ParseInt(v, 10, 64)
  1230. if err != nil {
  1231. http.Error(w, "can't parse expiry time, expects a unix timestamp", http.StatusBadRequest)
  1232. return
  1233. }
  1234. expiryTime = time.Unix(expiryInt, 0)
  1235. } else {
  1236. http.Error(w, "missing 'expiry' parameter, a unix timestamp", http.StatusBadRequest)
  1237. return
  1238. }
  1239. err := h.b.SetExpirySooner(r.Context(), expiryTime)
  1240. if err != nil {
  1241. http.Error(w, err.Error(), http.StatusBadRequest)
  1242. return
  1243. }
  1244. w.Header().Set("Content-Type", "text/plain")
  1245. io.WriteString(w, "done\n")
  1246. }
  1247. func (h *Handler) servePing(w http.ResponseWriter, r *http.Request) {
  1248. ctx := r.Context()
  1249. if r.Method != "POST" {
  1250. http.Error(w, "want POST", 400)
  1251. return
  1252. }
  1253. ipStr := r.FormValue("ip")
  1254. if ipStr == "" {
  1255. http.Error(w, "missing 'ip' parameter", 400)
  1256. return
  1257. }
  1258. ip, err := netip.ParseAddr(ipStr)
  1259. if err != nil {
  1260. http.Error(w, "invalid IP", 400)
  1261. return
  1262. }
  1263. pingTypeStr := r.FormValue("type")
  1264. if pingTypeStr == "" {
  1265. http.Error(w, "missing 'type' parameter", 400)
  1266. return
  1267. }
  1268. size := 0
  1269. sizeStr := r.FormValue("size")
  1270. if sizeStr != "" {
  1271. size, err = strconv.Atoi(sizeStr)
  1272. if err != nil {
  1273. http.Error(w, "invalid 'size' parameter", 400)
  1274. return
  1275. }
  1276. if size != 0 && tailcfg.PingType(pingTypeStr) != tailcfg.PingDisco {
  1277. http.Error(w, "'size' parameter is only supported with disco pings", 400)
  1278. return
  1279. }
  1280. if size > int(tstun.DefaultMTU()) {
  1281. http.Error(w, fmt.Sprintf("maximum value for 'size' is %v", tstun.DefaultMTU()), 400)
  1282. return
  1283. }
  1284. }
  1285. res, err := h.b.Ping(ctx, ip, tailcfg.PingType(pingTypeStr), size)
  1286. if err != nil {
  1287. writeErrorJSON(w, err)
  1288. return
  1289. }
  1290. w.Header().Set("Content-Type", "application/json")
  1291. json.NewEncoder(w).Encode(res)
  1292. }
  1293. func (h *Handler) serveDial(w http.ResponseWriter, r *http.Request) {
  1294. if r.Method != "POST" {
  1295. http.Error(w, "POST required", http.StatusMethodNotAllowed)
  1296. return
  1297. }
  1298. const upgradeProto = "ts-dial"
  1299. if !strings.Contains(r.Header.Get("Connection"), "upgrade") ||
  1300. r.Header.Get("Upgrade") != upgradeProto {
  1301. http.Error(w, "bad ts-dial upgrade", http.StatusBadRequest)
  1302. return
  1303. }
  1304. hostStr, portStr := r.Header.Get("Dial-Host"), r.Header.Get("Dial-Port")
  1305. if hostStr == "" || portStr == "" {
  1306. http.Error(w, "missing Dial-Host or Dial-Port header", http.StatusBadRequest)
  1307. return
  1308. }
  1309. hijacker, ok := w.(http.Hijacker)
  1310. if !ok {
  1311. http.Error(w, "make request over HTTP/1", http.StatusBadRequest)
  1312. return
  1313. }
  1314. addr := net.JoinHostPort(hostStr, portStr)
  1315. outConn, err := h.b.Dialer().UserDial(r.Context(), "tcp", addr)
  1316. if err != nil {
  1317. http.Error(w, "dial failure: "+err.Error(), http.StatusBadGateway)
  1318. return
  1319. }
  1320. defer outConn.Close()
  1321. w.Header().Set("Upgrade", upgradeProto)
  1322. w.Header().Set("Connection", "upgrade")
  1323. w.WriteHeader(http.StatusSwitchingProtocols)
  1324. reqConn, brw, err := hijacker.Hijack()
  1325. if err != nil {
  1326. h.logf("localapi dial Hijack error: %v", err)
  1327. return
  1328. }
  1329. defer reqConn.Close()
  1330. if err := brw.Flush(); err != nil {
  1331. return
  1332. }
  1333. reqConn = netutil.NewDrainBufConn(reqConn, brw.Reader)
  1334. errc := make(chan error, 1)
  1335. go func() {
  1336. _, err := io.Copy(reqConn, outConn)
  1337. errc <- err
  1338. }()
  1339. go func() {
  1340. _, err := io.Copy(outConn, reqConn)
  1341. errc <- err
  1342. }()
  1343. <-errc
  1344. }
  1345. func (h *Handler) serveSetPushDeviceToken(w http.ResponseWriter, r *http.Request) {
  1346. if !h.PermitWrite {
  1347. http.Error(w, "set push device token access denied", http.StatusForbidden)
  1348. return
  1349. }
  1350. if r.Method != "POST" {
  1351. http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
  1352. return
  1353. }
  1354. var params apitype.SetPushDeviceTokenRequest
  1355. if err := json.NewDecoder(r.Body).Decode(&params); err != nil {
  1356. http.Error(w, "invalid JSON body", 400)
  1357. return
  1358. }
  1359. hostinfo.SetPushDeviceToken(params.PushDeviceToken)
  1360. h.b.ResendHostinfoIfNeeded()
  1361. w.WriteHeader(http.StatusOK)
  1362. }
  1363. func (h *Handler) serveUploadClientMetrics(w http.ResponseWriter, r *http.Request) {
  1364. if r.Method != "POST" {
  1365. http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
  1366. return
  1367. }
  1368. type clientMetricJSON struct {
  1369. Name string `json:"name"`
  1370. Type string `json:"type"` // one of "counter" or "gauge"
  1371. Value int `json:"value"` // amount to increment metric by
  1372. }
  1373. var clientMetrics []clientMetricJSON
  1374. if err := json.NewDecoder(r.Body).Decode(&clientMetrics); err != nil {
  1375. http.Error(w, "invalid JSON body", 400)
  1376. return
  1377. }
  1378. metricsMu.Lock()
  1379. defer metricsMu.Unlock()
  1380. for _, m := range clientMetrics {
  1381. if metric, ok := metrics[m.Name]; ok {
  1382. metric.Add(int64(m.Value))
  1383. } else {
  1384. if clientmetric.HasPublished(m.Name) {
  1385. http.Error(w, "Already have a metric named "+m.Name, 400)
  1386. return
  1387. }
  1388. var metric *clientmetric.Metric
  1389. switch m.Type {
  1390. case "counter":
  1391. metric = clientmetric.NewCounter(m.Name)
  1392. case "gauge":
  1393. metric = clientmetric.NewGauge(m.Name)
  1394. default:
  1395. http.Error(w, "Unknown metric type "+m.Type, 400)
  1396. return
  1397. }
  1398. metrics[m.Name] = metric
  1399. metric.Add(int64(m.Value))
  1400. }
  1401. }
  1402. w.Header().Set("Content-Type", "application/json")
  1403. json.NewEncoder(w).Encode(struct{}{})
  1404. }
  1405. func (h *Handler) serveTKAStatus(w http.ResponseWriter, r *http.Request) {
  1406. if !h.PermitRead {
  1407. http.Error(w, "lock status access denied", http.StatusForbidden)
  1408. return
  1409. }
  1410. if r.Method != httpm.GET {
  1411. http.Error(w, "use GET", http.StatusMethodNotAllowed)
  1412. return
  1413. }
  1414. j, err := json.MarshalIndent(h.b.NetworkLockStatus(), "", "\t")
  1415. if err != nil {
  1416. http.Error(w, "JSON encoding error", 500)
  1417. return
  1418. }
  1419. w.Header().Set("Content-Type", "application/json")
  1420. w.Write(j)
  1421. }
  1422. func (h *Handler) serveTKASign(w http.ResponseWriter, r *http.Request) {
  1423. if !h.PermitRead {
  1424. http.Error(w, "lock status access denied", http.StatusForbidden)
  1425. return
  1426. }
  1427. if r.Method != httpm.POST {
  1428. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1429. return
  1430. }
  1431. type signRequest struct {
  1432. NodeKey key.NodePublic
  1433. RotationPublic []byte
  1434. }
  1435. var req signRequest
  1436. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  1437. http.Error(w, "invalid JSON body", http.StatusBadRequest)
  1438. return
  1439. }
  1440. if err := h.b.NetworkLockSign(req.NodeKey, req.RotationPublic); err != nil {
  1441. http.Error(w, "signing failed: "+err.Error(), http.StatusInternalServerError)
  1442. return
  1443. }
  1444. w.WriteHeader(http.StatusOK)
  1445. }
  1446. func (h *Handler) serveTKAInit(w http.ResponseWriter, r *http.Request) {
  1447. if !h.PermitWrite {
  1448. http.Error(w, "lock init access denied", http.StatusForbidden)
  1449. return
  1450. }
  1451. if r.Method != httpm.POST {
  1452. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1453. return
  1454. }
  1455. type initRequest struct {
  1456. Keys []tka.Key
  1457. DisablementValues [][]byte
  1458. SupportDisablement []byte
  1459. }
  1460. var req initRequest
  1461. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  1462. http.Error(w, "invalid JSON body", 400)
  1463. return
  1464. }
  1465. if err := h.b.NetworkLockInit(req.Keys, req.DisablementValues, req.SupportDisablement); err != nil {
  1466. http.Error(w, "initialization failed: "+err.Error(), http.StatusInternalServerError)
  1467. return
  1468. }
  1469. j, err := json.MarshalIndent(h.b.NetworkLockStatus(), "", "\t")
  1470. if err != nil {
  1471. http.Error(w, "JSON encoding error", 500)
  1472. return
  1473. }
  1474. w.Header().Set("Content-Type", "application/json")
  1475. w.Write(j)
  1476. }
  1477. func (h *Handler) serveTKAModify(w http.ResponseWriter, r *http.Request) {
  1478. if !h.PermitWrite {
  1479. http.Error(w, "network-lock modify access denied", http.StatusForbidden)
  1480. return
  1481. }
  1482. if r.Method != httpm.POST {
  1483. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1484. return
  1485. }
  1486. type modifyRequest struct {
  1487. AddKeys []tka.Key
  1488. RemoveKeys []tka.Key
  1489. }
  1490. var req modifyRequest
  1491. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  1492. http.Error(w, "invalid JSON body", 400)
  1493. return
  1494. }
  1495. if err := h.b.NetworkLockModify(req.AddKeys, req.RemoveKeys); err != nil {
  1496. http.Error(w, "network-lock modify failed: "+err.Error(), http.StatusInternalServerError)
  1497. return
  1498. }
  1499. w.WriteHeader(204)
  1500. }
  1501. func (h *Handler) serveTKAWrapPreauthKey(w http.ResponseWriter, r *http.Request) {
  1502. if !h.PermitWrite {
  1503. http.Error(w, "network-lock modify access denied", http.StatusForbidden)
  1504. return
  1505. }
  1506. if r.Method != httpm.POST {
  1507. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1508. return
  1509. }
  1510. type wrapRequest struct {
  1511. TSKey string
  1512. TKAKey string // key.NLPrivate.MarshalText
  1513. }
  1514. var req wrapRequest
  1515. if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 12*1024)).Decode(&req); err != nil {
  1516. http.Error(w, "invalid JSON body", http.StatusBadRequest)
  1517. return
  1518. }
  1519. var priv key.NLPrivate
  1520. if err := priv.UnmarshalText([]byte(req.TKAKey)); err != nil {
  1521. http.Error(w, "invalid JSON body", http.StatusBadRequest)
  1522. return
  1523. }
  1524. wrappedKey, err := h.b.NetworkLockWrapPreauthKey(req.TSKey, priv)
  1525. if err != nil {
  1526. http.Error(w, err.Error(), http.StatusInternalServerError)
  1527. return
  1528. }
  1529. w.WriteHeader(200)
  1530. w.Write([]byte(wrappedKey))
  1531. }
  1532. func (h *Handler) serveTKAVerifySigningDeeplink(w http.ResponseWriter, r *http.Request) {
  1533. if !h.PermitRead {
  1534. http.Error(w, "signing deeplink verification access denied", http.StatusForbidden)
  1535. return
  1536. }
  1537. if r.Method != httpm.POST {
  1538. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1539. return
  1540. }
  1541. type verifyRequest struct {
  1542. URL string
  1543. }
  1544. var req verifyRequest
  1545. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  1546. http.Error(w, "invalid JSON for verifyRequest body", 400)
  1547. return
  1548. }
  1549. res := h.b.NetworkLockVerifySigningDeeplink(req.URL)
  1550. j, err := json.MarshalIndent(res, "", "\t")
  1551. if err != nil {
  1552. http.Error(w, "JSON encoding error", 500)
  1553. return
  1554. }
  1555. w.Header().Set("Content-Type", "application/json")
  1556. w.Write(j)
  1557. }
  1558. func (h *Handler) serveTKADisable(w http.ResponseWriter, r *http.Request) {
  1559. if !h.PermitWrite {
  1560. http.Error(w, "network-lock modify access denied", http.StatusForbidden)
  1561. return
  1562. }
  1563. if r.Method != httpm.POST {
  1564. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1565. return
  1566. }
  1567. body := io.LimitReader(r.Body, 1024*1024)
  1568. secret, err := io.ReadAll(body)
  1569. if err != nil {
  1570. http.Error(w, "reading secret", 400)
  1571. return
  1572. }
  1573. if err := h.b.NetworkLockDisable(secret); err != nil {
  1574. http.Error(w, "network-lock disable failed: "+err.Error(), http.StatusBadRequest)
  1575. return
  1576. }
  1577. w.WriteHeader(200)
  1578. }
  1579. func (h *Handler) serveTKALocalDisable(w http.ResponseWriter, r *http.Request) {
  1580. if !h.PermitWrite {
  1581. http.Error(w, "network-lock modify access denied", http.StatusForbidden)
  1582. return
  1583. }
  1584. if r.Method != httpm.POST {
  1585. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1586. return
  1587. }
  1588. // Require a JSON stanza for the body as an additional CSRF protection.
  1589. var req struct{}
  1590. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  1591. http.Error(w, "invalid JSON body", 400)
  1592. return
  1593. }
  1594. if err := h.b.NetworkLockForceLocalDisable(); err != nil {
  1595. http.Error(w, "network-lock local disable failed: "+err.Error(), http.StatusBadRequest)
  1596. return
  1597. }
  1598. w.WriteHeader(200)
  1599. }
  1600. func (h *Handler) serveTKALog(w http.ResponseWriter, r *http.Request) {
  1601. if r.Method != httpm.GET {
  1602. http.Error(w, "use GET", http.StatusMethodNotAllowed)
  1603. return
  1604. }
  1605. limit := 50
  1606. if limitStr := r.FormValue("limit"); limitStr != "" {
  1607. l, err := strconv.Atoi(limitStr)
  1608. if err != nil {
  1609. http.Error(w, "parsing 'limit' parameter: "+err.Error(), http.StatusBadRequest)
  1610. return
  1611. }
  1612. limit = int(l)
  1613. }
  1614. updates, err := h.b.NetworkLockLog(limit)
  1615. if err != nil {
  1616. http.Error(w, "reading log failed: "+err.Error(), http.StatusInternalServerError)
  1617. return
  1618. }
  1619. j, err := json.MarshalIndent(updates, "", "\t")
  1620. if err != nil {
  1621. http.Error(w, "JSON encoding error", 500)
  1622. return
  1623. }
  1624. w.Header().Set("Content-Type", "application/json")
  1625. w.Write(j)
  1626. }
  1627. func (h *Handler) serveTKAAffectedSigs(w http.ResponseWriter, r *http.Request) {
  1628. if r.Method != httpm.POST {
  1629. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1630. return
  1631. }
  1632. keyID, err := io.ReadAll(http.MaxBytesReader(w, r.Body, 2048))
  1633. if err != nil {
  1634. http.Error(w, "reading body", http.StatusBadRequest)
  1635. return
  1636. }
  1637. sigs, err := h.b.NetworkLockAffectedSigs(keyID)
  1638. if err != nil {
  1639. http.Error(w, err.Error(), http.StatusInternalServerError)
  1640. return
  1641. }
  1642. j, err := json.MarshalIndent(sigs, "", "\t")
  1643. if err != nil {
  1644. http.Error(w, "JSON encoding error", http.StatusInternalServerError)
  1645. return
  1646. }
  1647. w.Header().Set("Content-Type", "application/json")
  1648. w.Write(j)
  1649. }
  1650. func (h *Handler) serveTKAGenerateRecoveryAUM(w http.ResponseWriter, r *http.Request) {
  1651. if !h.PermitWrite {
  1652. http.Error(w, "access denied", http.StatusForbidden)
  1653. return
  1654. }
  1655. if r.Method != httpm.POST {
  1656. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1657. return
  1658. }
  1659. type verifyRequest struct {
  1660. Keys []tkatype.KeyID
  1661. ForkFrom string
  1662. }
  1663. var req verifyRequest
  1664. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  1665. http.Error(w, "invalid JSON for verifyRequest body", http.StatusBadRequest)
  1666. return
  1667. }
  1668. var forkFrom tka.AUMHash
  1669. if req.ForkFrom != "" {
  1670. if err := forkFrom.UnmarshalText([]byte(req.ForkFrom)); err != nil {
  1671. http.Error(w, "decoding fork-from: "+err.Error(), http.StatusBadRequest)
  1672. return
  1673. }
  1674. }
  1675. res, err := h.b.NetworkLockGenerateRecoveryAUM(req.Keys, forkFrom)
  1676. if err != nil {
  1677. http.Error(w, err.Error(), 500)
  1678. return
  1679. }
  1680. w.Header().Set("Content-Type", "application/octet-stream")
  1681. w.Write(res.Serialize())
  1682. }
  1683. func (h *Handler) serveTKACosignRecoveryAUM(w http.ResponseWriter, r *http.Request) {
  1684. if !h.PermitWrite {
  1685. http.Error(w, "access denied", http.StatusForbidden)
  1686. return
  1687. }
  1688. if r.Method != httpm.POST {
  1689. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1690. return
  1691. }
  1692. body := io.LimitReader(r.Body, 1024*1024)
  1693. aumBytes, err := io.ReadAll(body)
  1694. if err != nil {
  1695. http.Error(w, "reading AUM", http.StatusBadRequest)
  1696. return
  1697. }
  1698. var aum tka.AUM
  1699. if err := aum.Unserialize(aumBytes); err != nil {
  1700. http.Error(w, "decoding AUM", http.StatusBadRequest)
  1701. return
  1702. }
  1703. res, err := h.b.NetworkLockCosignRecoveryAUM(&aum)
  1704. if err != nil {
  1705. http.Error(w, err.Error(), http.StatusInternalServerError)
  1706. return
  1707. }
  1708. w.Header().Set("Content-Type", "application/octet-stream")
  1709. w.Write(res.Serialize())
  1710. }
  1711. func (h *Handler) serveTKASubmitRecoveryAUM(w http.ResponseWriter, r *http.Request) {
  1712. if !h.PermitWrite {
  1713. http.Error(w, "access denied", http.StatusForbidden)
  1714. return
  1715. }
  1716. if r.Method != httpm.POST {
  1717. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1718. return
  1719. }
  1720. body := io.LimitReader(r.Body, 1024*1024)
  1721. aumBytes, err := io.ReadAll(body)
  1722. if err != nil {
  1723. http.Error(w, "reading AUM", http.StatusBadRequest)
  1724. return
  1725. }
  1726. var aum tka.AUM
  1727. if err := aum.Unserialize(aumBytes); err != nil {
  1728. http.Error(w, "decoding AUM", http.StatusBadRequest)
  1729. return
  1730. }
  1731. if err := h.b.NetworkLockSubmitRecoveryAUM(&aum); err != nil {
  1732. http.Error(w, err.Error(), http.StatusInternalServerError)
  1733. return
  1734. }
  1735. w.WriteHeader(http.StatusOK)
  1736. }
  1737. // serveProfiles serves profile switching-related endpoints. Supported methods
  1738. // and paths are:
  1739. // - GET /profiles/: list all profiles (JSON-encoded array of ipn.LoginProfiles)
  1740. // - PUT /profiles/: add new profile (no response). A separate
  1741. // StartLoginInteractive() is needed to populate and persist the new profile.
  1742. // - GET /profiles/current: current profile (JSON-ecoded ipn.LoginProfile)
  1743. // - GET /profiles/<id>: output profile (JSON-ecoded ipn.LoginProfile)
  1744. // - POST /profiles/<id>: switch to profile (no response)
  1745. // - DELETE /profiles/<id>: delete profile (no response)
  1746. func (h *Handler) serveProfiles(w http.ResponseWriter, r *http.Request) {
  1747. if !h.PermitWrite {
  1748. http.Error(w, "profiles access denied", http.StatusForbidden)
  1749. return
  1750. }
  1751. suffix, ok := strings.CutPrefix(r.URL.EscapedPath(), "/localapi/v0/profiles/")
  1752. if !ok {
  1753. http.Error(w, "misconfigured", http.StatusInternalServerError)
  1754. return
  1755. }
  1756. if suffix == "" {
  1757. switch r.Method {
  1758. case httpm.GET:
  1759. w.Header().Set("Content-Type", "application/json")
  1760. json.NewEncoder(w).Encode(h.b.ListProfiles())
  1761. case httpm.PUT:
  1762. err := h.b.NewProfile()
  1763. if err != nil {
  1764. http.Error(w, err.Error(), http.StatusInternalServerError)
  1765. return
  1766. }
  1767. w.WriteHeader(http.StatusCreated)
  1768. default:
  1769. http.Error(w, "use GET or PUT", http.StatusMethodNotAllowed)
  1770. }
  1771. return
  1772. }
  1773. suffix, err := url.PathUnescape(suffix)
  1774. if err != nil {
  1775. http.Error(w, "bad profile ID", http.StatusBadRequest)
  1776. return
  1777. }
  1778. if suffix == "current" {
  1779. switch r.Method {
  1780. case httpm.GET:
  1781. w.Header().Set("Content-Type", "application/json")
  1782. json.NewEncoder(w).Encode(h.b.CurrentProfile())
  1783. default:
  1784. http.Error(w, "use GET", http.StatusMethodNotAllowed)
  1785. }
  1786. return
  1787. }
  1788. profileID := ipn.ProfileID(suffix)
  1789. switch r.Method {
  1790. case httpm.GET:
  1791. profiles := h.b.ListProfiles()
  1792. profileIndex := slices.IndexFunc(profiles, func(p ipn.LoginProfile) bool {
  1793. return p.ID == profileID
  1794. })
  1795. if profileIndex == -1 {
  1796. http.Error(w, "Profile not found", http.StatusNotFound)
  1797. return
  1798. }
  1799. w.Header().Set("Content-Type", "application/json")
  1800. json.NewEncoder(w).Encode(profiles[profileIndex])
  1801. case httpm.POST:
  1802. err := h.b.SwitchProfile(profileID)
  1803. if err != nil {
  1804. http.Error(w, err.Error(), http.StatusInternalServerError)
  1805. return
  1806. }
  1807. w.WriteHeader(http.StatusNoContent)
  1808. case httpm.DELETE:
  1809. err := h.b.DeleteProfile(profileID)
  1810. if err != nil {
  1811. http.Error(w, err.Error(), http.StatusInternalServerError)
  1812. return
  1813. }
  1814. w.WriteHeader(http.StatusNoContent)
  1815. default:
  1816. http.Error(w, "use POST or DELETE", http.StatusMethodNotAllowed)
  1817. }
  1818. }
  1819. // serveQueryFeature makes a request to the "/machine/feature/query"
  1820. // Noise endpoint to get instructions on how to enable a feature, such as
  1821. // Funnel, for the node's tailnet.
  1822. //
  1823. // This request itself does not directly enable the feature on behalf of
  1824. // the node, but rather returns information that can be presented to the
  1825. // acting user about where/how to enable the feature. If relevant, this
  1826. // includes a control URL the user can visit to explicitly consent to
  1827. // using the feature.
  1828. //
  1829. // See tailcfg.QueryFeatureResponse for full response structure.
  1830. func (h *Handler) serveQueryFeature(w http.ResponseWriter, r *http.Request) {
  1831. feature := r.FormValue("feature")
  1832. switch {
  1833. case !h.PermitRead:
  1834. http.Error(w, "access denied", http.StatusForbidden)
  1835. return
  1836. case r.Method != httpm.POST:
  1837. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1838. return
  1839. case feature == "":
  1840. http.Error(w, "missing feature", http.StatusInternalServerError)
  1841. return
  1842. }
  1843. nm := h.b.NetMap()
  1844. if nm == nil {
  1845. http.Error(w, "no netmap", http.StatusServiceUnavailable)
  1846. return
  1847. }
  1848. b, err := json.Marshal(&tailcfg.QueryFeatureRequest{
  1849. NodeKey: nm.NodeKey,
  1850. Feature: feature,
  1851. })
  1852. if err != nil {
  1853. http.Error(w, err.Error(), http.StatusInternalServerError)
  1854. return
  1855. }
  1856. req, err := http.NewRequestWithContext(r.Context(),
  1857. "POST", "https://unused/machine/feature/query", bytes.NewReader(b))
  1858. if err != nil {
  1859. http.Error(w, err.Error(), http.StatusInternalServerError)
  1860. return
  1861. }
  1862. resp, err := h.b.DoNoiseRequest(req)
  1863. if err != nil {
  1864. http.Error(w, err.Error(), http.StatusInternalServerError)
  1865. return
  1866. }
  1867. defer resp.Body.Close()
  1868. w.Header().Set("Content-Type", "application/json")
  1869. w.WriteHeader(resp.StatusCode)
  1870. if _, err := io.Copy(w, resp.Body); err != nil {
  1871. http.Error(w, err.Error(), http.StatusInternalServerError)
  1872. return
  1873. }
  1874. }
  1875. func defBool(a string, def bool) bool {
  1876. if a == "" {
  1877. return def
  1878. }
  1879. v, err := strconv.ParseBool(a)
  1880. if err != nil {
  1881. return def
  1882. }
  1883. return v
  1884. }
  1885. func (h *Handler) serveDebugCapture(w http.ResponseWriter, r *http.Request) {
  1886. if !h.PermitWrite {
  1887. http.Error(w, "debug access denied", http.StatusForbidden)
  1888. return
  1889. }
  1890. if r.Method != "POST" {
  1891. http.Error(w, "POST required", http.StatusMethodNotAllowed)
  1892. return
  1893. }
  1894. w.WriteHeader(200)
  1895. w.(http.Flusher).Flush()
  1896. h.b.StreamDebugCapture(r.Context(), w)
  1897. }
  1898. func (h *Handler) serveDebugLog(w http.ResponseWriter, r *http.Request) {
  1899. if !h.PermitRead {
  1900. http.Error(w, "debug-log access denied", http.StatusForbidden)
  1901. return
  1902. }
  1903. if r.Method != httpm.POST {
  1904. http.Error(w, "only POST allowed", http.StatusMethodNotAllowed)
  1905. return
  1906. }
  1907. defer h.b.TryFlushLogs() // kick off upload after we're done logging
  1908. type logRequestJSON struct {
  1909. Lines []string
  1910. Prefix string
  1911. }
  1912. var logRequest logRequestJSON
  1913. if err := json.NewDecoder(r.Body).Decode(&logRequest); err != nil {
  1914. http.Error(w, "invalid JSON body", 400)
  1915. return
  1916. }
  1917. prefix := logRequest.Prefix
  1918. if prefix == "" {
  1919. prefix = "debug-log"
  1920. }
  1921. logf := logger.WithPrefix(h.logf, prefix+": ")
  1922. // We can write logs too fast for logtail to handle, even when
  1923. // opting-out of rate limits. Limit ourselves to at most one message
  1924. // per 20ms and a burst of 60 log lines, which should be fast enough to
  1925. // not block for too long but slow enough that we can upload all lines.
  1926. logf = logger.SlowLoggerWithClock(r.Context(), logf, 20*time.Millisecond, 60, h.clock.Now)
  1927. for _, line := range logRequest.Lines {
  1928. logf("%s", line)
  1929. }
  1930. w.WriteHeader(http.StatusNoContent)
  1931. }
  1932. var (
  1933. metricInvalidRequests = clientmetric.NewCounter("localapi_invalid_requests")
  1934. // User-visible LocalAPI endpoints.
  1935. metricFilePutCalls = clientmetric.NewCounter("localapi_file_put")
  1936. )