localapi.go 80 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826
  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. "cmp"
  8. "context"
  9. "crypto/sha256"
  10. "encoding/hex"
  11. "encoding/json"
  12. "errors"
  13. "fmt"
  14. "io"
  15. "net"
  16. "net/http"
  17. "net/netip"
  18. "net/url"
  19. "os"
  20. "path"
  21. "reflect"
  22. "runtime"
  23. "slices"
  24. "strconv"
  25. "strings"
  26. "sync"
  27. "time"
  28. "golang.org/x/net/dns/dnsmessage"
  29. "tailscale.com/client/tailscale/apitype"
  30. "tailscale.com/clientupdate"
  31. "tailscale.com/drive"
  32. "tailscale.com/envknob"
  33. "tailscale.com/health/healthmsg"
  34. "tailscale.com/hostinfo"
  35. "tailscale.com/ipn"
  36. "tailscale.com/ipn/ipnauth"
  37. "tailscale.com/ipn/ipnlocal"
  38. "tailscale.com/ipn/ipnstate"
  39. "tailscale.com/logtail"
  40. "tailscale.com/net/netmon"
  41. "tailscale.com/net/netutil"
  42. "tailscale.com/net/portmapper"
  43. "tailscale.com/tailcfg"
  44. "tailscale.com/tka"
  45. "tailscale.com/tstime"
  46. "tailscale.com/types/dnstype"
  47. "tailscale.com/types/key"
  48. "tailscale.com/types/logger"
  49. "tailscale.com/types/logid"
  50. "tailscale.com/types/ptr"
  51. "tailscale.com/types/tkatype"
  52. "tailscale.com/util/clientmetric"
  53. "tailscale.com/util/eventbus"
  54. "tailscale.com/util/httpm"
  55. "tailscale.com/util/mak"
  56. "tailscale.com/util/osdiag"
  57. "tailscale.com/util/rands"
  58. "tailscale.com/util/syspolicy/rsop"
  59. "tailscale.com/util/syspolicy/setting"
  60. "tailscale.com/version"
  61. "tailscale.com/wgengine/magicsock"
  62. )
  63. var (
  64. metricInvalidRequests = clientmetric.NewCounter("localapi_invalid_requests")
  65. metricDebugMetricsCalls = clientmetric.NewCounter("localapi_debugmetric_requests")
  66. metricUserMetricsCalls = clientmetric.NewCounter("localapi_usermetric_requests")
  67. metricBugReportRequests = clientmetric.NewCounter("localapi_bugreport_requests")
  68. )
  69. type LocalAPIHandler func(*Handler, http.ResponseWriter, *http.Request)
  70. // handler is the set of LocalAPI handlers, keyed by the part of the
  71. // Request.URL.Path after "/localapi/v0/". If the key ends with a trailing slash
  72. // then it's a prefix match.
  73. var handler = map[string]LocalAPIHandler{
  74. // The prefix match handlers end with a slash:
  75. "cert/": (*Handler).serveCert,
  76. "policy/": (*Handler).servePolicy,
  77. "profiles/": (*Handler).serveProfiles,
  78. // The other /localapi/v0/NAME handlers are exact matches and contain only NAME
  79. // without a trailing slash:
  80. "alpha-set-device-attrs": (*Handler).serveSetDeviceAttrs, // see tailscale/corp#24690
  81. "bugreport": (*Handler).serveBugReport,
  82. "check-ip-forwarding": (*Handler).serveCheckIPForwarding,
  83. "check-prefs": (*Handler).serveCheckPrefs,
  84. "check-reverse-path-filtering": (*Handler).serveCheckReversePathFiltering,
  85. "check-udp-gro-forwarding": (*Handler).serveCheckUDPGROForwarding,
  86. "component-debug-logging": (*Handler).serveComponentDebugLogging,
  87. "debug": (*Handler).serveDebug,
  88. "debug-bus-events": (*Handler).serveDebugBusEvents,
  89. "debug-bus-graph": (*Handler).serveEventBusGraph,
  90. "debug-derp-region": (*Handler).serveDebugDERPRegion,
  91. "debug-dial-types": (*Handler).serveDebugDialTypes,
  92. "debug-log": (*Handler).serveDebugLog,
  93. "debug-packet-filter-matches": (*Handler).serveDebugPacketFilterMatches,
  94. "debug-packet-filter-rules": (*Handler).serveDebugPacketFilterRules,
  95. "debug-peer-endpoint-changes": (*Handler).serveDebugPeerEndpointChanges,
  96. "debug-portmap": (*Handler).serveDebugPortmap,
  97. "derpmap": (*Handler).serveDERPMap,
  98. "dev-set-state-store": (*Handler).serveDevSetStateStore,
  99. "dial": (*Handler).serveDial,
  100. "disconnect-control": (*Handler).disconnectControl,
  101. "dns-osconfig": (*Handler).serveDNSOSConfig,
  102. "dns-query": (*Handler).serveDNSQuery,
  103. "drive/fileserver-address": (*Handler).serveDriveServerAddr,
  104. "drive/shares": (*Handler).serveShares,
  105. "goroutines": (*Handler).serveGoroutines,
  106. "handle-push-message": (*Handler).serveHandlePushMessage,
  107. "id-token": (*Handler).serveIDToken,
  108. "login-interactive": (*Handler).serveLoginInteractive,
  109. "logout": (*Handler).serveLogout,
  110. "logtap": (*Handler).serveLogTap,
  111. "metrics": (*Handler).serveMetrics,
  112. "ping": (*Handler).servePing,
  113. "pprof": (*Handler).servePprof,
  114. "prefs": (*Handler).servePrefs,
  115. "query-feature": (*Handler).serveQueryFeature,
  116. "reload-config": (*Handler).reloadConfig,
  117. "reset-auth": (*Handler).serveResetAuth,
  118. "serve-config": (*Handler).serveServeConfig,
  119. "set-dns": (*Handler).serveSetDNS,
  120. "set-expiry-sooner": (*Handler).serveSetExpirySooner,
  121. "set-gui-visible": (*Handler).serveSetGUIVisible,
  122. "set-push-device-token": (*Handler).serveSetPushDeviceToken,
  123. "set-udp-gro-forwarding": (*Handler).serveSetUDPGROForwarding,
  124. "set-use-exit-node-enabled": (*Handler).serveSetUseExitNodeEnabled,
  125. "start": (*Handler).serveStart,
  126. "status": (*Handler).serveStatus,
  127. "suggest-exit-node": (*Handler).serveSuggestExitNode,
  128. "tka/affected-sigs": (*Handler).serveTKAAffectedSigs,
  129. "tka/cosign-recovery-aum": (*Handler).serveTKACosignRecoveryAUM,
  130. "tka/disable": (*Handler).serveTKADisable,
  131. "tka/force-local-disable": (*Handler).serveTKALocalDisable,
  132. "tka/generate-recovery-aum": (*Handler).serveTKAGenerateRecoveryAUM,
  133. "tka/init": (*Handler).serveTKAInit,
  134. "tka/log": (*Handler).serveTKALog,
  135. "tka/modify": (*Handler).serveTKAModify,
  136. "tka/sign": (*Handler).serveTKASign,
  137. "tka/status": (*Handler).serveTKAStatus,
  138. "tka/submit-recovery-aum": (*Handler).serveTKASubmitRecoveryAUM,
  139. "tka/verify-deeplink": (*Handler).serveTKAVerifySigningDeeplink,
  140. "tka/wrap-preauth-key": (*Handler).serveTKAWrapPreauthKey,
  141. "update/check": (*Handler).serveUpdateCheck,
  142. "update/install": (*Handler).serveUpdateInstall,
  143. "update/progress": (*Handler).serveUpdateProgress,
  144. "upload-client-metrics": (*Handler).serveUploadClientMetrics,
  145. "usermetrics": (*Handler).serveUserMetrics,
  146. "watch-ipn-bus": (*Handler).serveWatchIPNBus,
  147. "whois": (*Handler).serveWhoIs,
  148. }
  149. // Register registers a new LocalAPI handler for the given name.
  150. func Register(name string, fn LocalAPIHandler) {
  151. if _, ok := handler[name]; ok {
  152. panic("duplicate LocalAPI handler registration: " + name)
  153. }
  154. handler[name] = fn
  155. }
  156. var (
  157. // The clientmetrics package is stateful, but we want to expose a simple
  158. // imperative API to local clients, so we need to keep track of
  159. // clientmetric.Metric instances that we've created for them. These need to
  160. // be globals because we end up creating many Handler instances for the
  161. // lifetime of a client.
  162. metricsMu sync.Mutex
  163. metrics = map[string]*clientmetric.Metric{}
  164. )
  165. // NewHandler creates a new LocalAPI HTTP handler. All parameters are required.
  166. func NewHandler(actor ipnauth.Actor, b *ipnlocal.LocalBackend, logf logger.Logf, logID logid.PublicID) *Handler {
  167. return &Handler{Actor: actor, b: b, logf: logf, backendLogID: logID, clock: tstime.StdClock{}}
  168. }
  169. type Handler struct {
  170. // RequiredPassword, if non-empty, forces all HTTP
  171. // requests to have HTTP basic auth with this password.
  172. // It's used by the sandboxed macOS sameuserproof GUI auth mechanism.
  173. RequiredPassword string
  174. // PermitRead is whether read-only HTTP handlers are allowed.
  175. PermitRead bool
  176. // PermitWrite is whether mutating HTTP handlers are allowed.
  177. // If PermitWrite is true, everything is allowed.
  178. // It effectively means that the user is root or the admin
  179. // (operator user).
  180. PermitWrite bool
  181. // PermitCert is whether the client is additionally granted
  182. // cert fetching access.
  183. PermitCert bool
  184. // Actor is the identity of the client connected to the Handler.
  185. Actor ipnauth.Actor
  186. b *ipnlocal.LocalBackend
  187. logf logger.Logf
  188. backendLogID logid.PublicID
  189. clock tstime.Clock
  190. }
  191. func (h *Handler) Logf(format string, args ...any) {
  192. h.logf(format, args...)
  193. }
  194. func (h *Handler) LocalBackend() *ipnlocal.LocalBackend {
  195. return h.b
  196. }
  197. func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  198. if h.b == nil {
  199. http.Error(w, "server has no local backend", http.StatusInternalServerError)
  200. return
  201. }
  202. if r.Referer() != "" || r.Header.Get("Origin") != "" || !h.validHost(r.Host) {
  203. metricInvalidRequests.Add(1)
  204. http.Error(w, "invalid localapi request", http.StatusForbidden)
  205. return
  206. }
  207. w.Header().Set("Tailscale-Version", version.Long())
  208. w.Header().Set("Tailscale-Cap", strconv.Itoa(int(tailcfg.CurrentCapabilityVersion)))
  209. w.Header().Set("Content-Security-Policy", `default-src 'none'; frame-ancestors 'none'; script-src 'none'; script-src-elem 'none'; script-src-attr 'none'`)
  210. w.Header().Set("X-Frame-Options", "DENY")
  211. w.Header().Set("X-Content-Type-Options", "nosniff")
  212. if h.RequiredPassword != "" {
  213. _, pass, ok := r.BasicAuth()
  214. if !ok {
  215. metricInvalidRequests.Add(1)
  216. http.Error(w, "auth required", http.StatusUnauthorized)
  217. return
  218. }
  219. if pass != h.RequiredPassword {
  220. metricInvalidRequests.Add(1)
  221. http.Error(w, "bad password", http.StatusForbidden)
  222. return
  223. }
  224. }
  225. if fn, ok := handlerForPath(r.URL.Path); ok {
  226. fn(h, w, r)
  227. } else {
  228. http.NotFound(w, r)
  229. }
  230. }
  231. // validLocalHostForTesting allows loopback handlers without RequiredPassword for testing.
  232. var validLocalHostForTesting = false
  233. // validHost reports whether h is a valid Host header value for a LocalAPI request.
  234. func (h *Handler) validHost(hostname string) bool {
  235. // The client code sends a hostname of "local-tailscaled.sock".
  236. switch hostname {
  237. case "", apitype.LocalAPIHost:
  238. return true
  239. }
  240. if !validLocalHostForTesting && h.RequiredPassword == "" {
  241. return false // only allow localhost with basic auth or in tests
  242. }
  243. host, _, err := net.SplitHostPort(hostname)
  244. if err != nil {
  245. return false
  246. }
  247. if host == "localhost" {
  248. return true
  249. }
  250. addr, err := netip.ParseAddr(host)
  251. if err != nil {
  252. return false
  253. }
  254. return addr.IsLoopback()
  255. }
  256. // handlerForPath returns the LocalAPI handler for the provided Request.URI.Path.
  257. // (the path doesn't include any query parameters)
  258. func handlerForPath(urlPath string) (h LocalAPIHandler, ok bool) {
  259. if urlPath == "/" {
  260. return (*Handler).serveLocalAPIRoot, true
  261. }
  262. suff, ok := strings.CutPrefix(urlPath, "/localapi/v0/")
  263. if !ok {
  264. // Currently all LocalAPI methods start with "/localapi/v0/" to signal
  265. // to people that they're not necessarily stable APIs. In practice we'll
  266. // probably need to keep them pretty stable anyway, but for now treat
  267. // them as an internal implementation detail.
  268. return nil, false
  269. }
  270. if fn, ok := handler[suff]; ok {
  271. // Here we match exact handler suffixes like "status" or ones with a
  272. // slash already in their name, like "tka/status".
  273. return fn, true
  274. }
  275. // Otherwise, it might be a prefix match like "files/*" which we look up
  276. // by the prefix including first trailing slash.
  277. if i := strings.IndexByte(suff, '/'); i != -1 {
  278. suff = suff[:i+1]
  279. if fn, ok := handler[suff]; ok {
  280. return fn, true
  281. }
  282. }
  283. return nil, false
  284. }
  285. func (*Handler) serveLocalAPIRoot(w http.ResponseWriter, r *http.Request) {
  286. io.WriteString(w, "tailscaled\n")
  287. }
  288. // serveIDToken handles requests to get an OIDC ID token.
  289. func (h *Handler) serveIDToken(w http.ResponseWriter, r *http.Request) {
  290. if !h.PermitWrite {
  291. http.Error(w, "id-token access denied", http.StatusForbidden)
  292. return
  293. }
  294. nm := h.b.NetMap()
  295. if nm == nil {
  296. http.Error(w, "no netmap", http.StatusServiceUnavailable)
  297. return
  298. }
  299. aud := strings.TrimSpace(r.FormValue("aud"))
  300. if len(aud) == 0 {
  301. http.Error(w, "no audience requested", http.StatusBadRequest)
  302. return
  303. }
  304. req := &tailcfg.TokenRequest{
  305. CapVersion: tailcfg.CurrentCapabilityVersion,
  306. Audience: aud,
  307. NodeKey: nm.NodeKey,
  308. }
  309. b, err := json.Marshal(req)
  310. if err != nil {
  311. http.Error(w, err.Error(), http.StatusInternalServerError)
  312. return
  313. }
  314. httpReq, err := http.NewRequest(httpm.POST, "https://unused/machine/id-token", bytes.NewReader(b))
  315. if err != nil {
  316. http.Error(w, err.Error(), http.StatusInternalServerError)
  317. return
  318. }
  319. resp, err := h.b.DoNoiseRequest(httpReq)
  320. if err != nil {
  321. http.Error(w, err.Error(), http.StatusInternalServerError)
  322. return
  323. }
  324. defer resp.Body.Close()
  325. w.WriteHeader(resp.StatusCode)
  326. if _, err := io.Copy(w, resp.Body); err != nil {
  327. http.Error(w, err.Error(), http.StatusInternalServerError)
  328. return
  329. }
  330. }
  331. func (h *Handler) serveBugReport(w http.ResponseWriter, r *http.Request) {
  332. if !h.PermitRead {
  333. http.Error(w, "bugreport access denied", http.StatusForbidden)
  334. return
  335. }
  336. if r.Method != httpm.POST {
  337. http.Error(w, "only POST allowed", http.StatusMethodNotAllowed)
  338. return
  339. }
  340. defer h.b.TryFlushLogs() // kick off upload after bugreport's done logging
  341. logMarker := func() string {
  342. return fmt.Sprintf("BUG-%v-%v-%v", h.backendLogID, h.clock.Now().UTC().Format("20060102150405Z"), rands.HexString(16))
  343. }
  344. if envknob.NoLogsNoSupport() {
  345. logMarker = func() string { return "BUG-NO-LOGS-NO-SUPPORT-this-node-has-had-its-logging-disabled" }
  346. }
  347. startMarker := logMarker()
  348. h.logf("user bugreport: %s", startMarker)
  349. if note := r.URL.Query().Get("note"); len(note) > 0 {
  350. h.logf("user bugreport note: %s", note)
  351. }
  352. hi, _ := json.Marshal(hostinfo.New())
  353. h.logf("user bugreport hostinfo: %s", hi)
  354. if err := h.b.HealthTracker().OverallError(); err != nil {
  355. h.logf("user bugreport health: %s", err.Error())
  356. } else {
  357. h.logf("user bugreport health: ok")
  358. }
  359. // Information about the current node from the netmap
  360. if nm := h.b.NetMap(); nm != nil {
  361. if self := nm.SelfNode; self.Valid() {
  362. h.logf("user bugreport node info: nodeid=%q stableid=%q expiry=%q", self.ID(), self.StableID(), self.KeyExpiry().Format(time.RFC3339))
  363. }
  364. h.logf("user bugreport public keys: machine=%q node=%q", nm.MachineKey, nm.NodeKey)
  365. } else {
  366. h.logf("user bugreport netmap: no active netmap")
  367. }
  368. // Print all envknobs; we otherwise only print these on startup, and
  369. // printing them here ensures we don't have to go spelunking through
  370. // logs for them.
  371. envknob.LogCurrent(logger.WithPrefix(h.logf, "user bugreport: "))
  372. // OS-specific details
  373. h.logf.JSON(1, "UserBugReportOS", osdiag.SupportInfo(osdiag.LogSupportInfoReasonBugReport))
  374. // Tailnet lock details
  375. st := h.b.NetworkLockStatus()
  376. if st.Enabled {
  377. h.logf.JSON(1, "UserBugReportTailnetLockStatus", st)
  378. if st.NodeKeySignature != nil {
  379. h.logf("user bugreport tailnet lock signature: %s", st.NodeKeySignature.String())
  380. }
  381. }
  382. if defBool(r.URL.Query().Get("diagnose"), false) {
  383. h.b.Doctor(r.Context(), logger.WithPrefix(h.logf, "diag: "))
  384. }
  385. w.Header().Set("Content-Type", "text/plain")
  386. fmt.Fprintln(w, startMarker)
  387. // Nothing else to do if we're not in record mode; we wrote the marker
  388. // above, so we can just finish our response now.
  389. if !defBool(r.URL.Query().Get("record"), false) {
  390. return
  391. }
  392. until := h.clock.Now().Add(12 * time.Hour)
  393. var changed map[string]bool
  394. for _, component := range []string{"magicsock"} {
  395. if h.b.GetComponentDebugLogging(component).IsZero() {
  396. if err := h.b.SetComponentDebugLogging(component, until); err != nil {
  397. h.logf("bugreport: error setting component %q logging: %v", component, err)
  398. continue
  399. }
  400. mak.Set(&changed, component, true)
  401. }
  402. }
  403. defer func() {
  404. for component := range changed {
  405. h.b.SetComponentDebugLogging(component, time.Time{})
  406. }
  407. }()
  408. // NOTE(andrew): if we have anything else we want to do while recording
  409. // a bugreport, we can add it here.
  410. metricBugReportRequests.Add(1)
  411. // Read from the client; this will also return when the client closes
  412. // the connection.
  413. var buf [1]byte
  414. _, err := r.Body.Read(buf[:])
  415. switch {
  416. case err == nil:
  417. // good
  418. case errors.Is(err, io.EOF):
  419. // good
  420. case errors.Is(err, io.ErrUnexpectedEOF):
  421. // this happens when Ctrl-C'ing the tailscale client; don't
  422. // bother logging an error
  423. default:
  424. // Log but continue anyway.
  425. h.logf("user bugreport: error reading body: %v", err)
  426. }
  427. // Generate another log marker and return it to the client.
  428. endMarker := logMarker()
  429. h.logf("user bugreport end: %s", endMarker)
  430. fmt.Fprintln(w, endMarker)
  431. }
  432. func (h *Handler) serveWhoIs(w http.ResponseWriter, r *http.Request) {
  433. h.serveWhoIsWithBackend(w, r, h.b)
  434. }
  435. // serveSetDeviceAttrs is (as of 2024-12-30) an experimental LocalAPI handler to
  436. // set device attributes via the control plane.
  437. //
  438. // See tailscale/corp#24690.
  439. func (h *Handler) serveSetDeviceAttrs(w http.ResponseWriter, r *http.Request) {
  440. ctx := r.Context()
  441. if !h.PermitWrite {
  442. http.Error(w, "set-device-attrs access denied", http.StatusForbidden)
  443. return
  444. }
  445. if r.Method != httpm.PATCH {
  446. http.Error(w, "only PATCH allowed", http.StatusMethodNotAllowed)
  447. return
  448. }
  449. var req map[string]any
  450. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  451. http.Error(w, err.Error(), http.StatusBadRequest)
  452. return
  453. }
  454. if err := h.b.SetDeviceAttrs(ctx, req); err != nil {
  455. http.Error(w, err.Error(), http.StatusInternalServerError)
  456. return
  457. }
  458. w.Header().Set("Content-Type", "application/json")
  459. io.WriteString(w, "{}\n")
  460. }
  461. // localBackendWhoIsMethods is the subset of ipn.LocalBackend as needed
  462. // by the localapi WhoIs method.
  463. type localBackendWhoIsMethods interface {
  464. WhoIs(string, netip.AddrPort) (n tailcfg.NodeView, u tailcfg.UserProfile, ok bool)
  465. WhoIsNodeKey(key.NodePublic) (n tailcfg.NodeView, u tailcfg.UserProfile, ok bool)
  466. PeerCaps(netip.Addr) tailcfg.PeerCapMap
  467. }
  468. func (h *Handler) serveWhoIsWithBackend(w http.ResponseWriter, r *http.Request, b localBackendWhoIsMethods) {
  469. if !h.PermitRead {
  470. http.Error(w, "whois access denied", http.StatusForbidden)
  471. return
  472. }
  473. var (
  474. n tailcfg.NodeView
  475. u tailcfg.UserProfile
  476. ok bool
  477. )
  478. var ipp netip.AddrPort
  479. if v := r.FormValue("addr"); v != "" {
  480. if strings.HasPrefix(v, "nodekey:") {
  481. var k key.NodePublic
  482. if err := k.UnmarshalText([]byte(v)); err != nil {
  483. http.Error(w, "invalid nodekey in 'addr' parameter", http.StatusBadRequest)
  484. return
  485. }
  486. n, u, ok = b.WhoIsNodeKey(k)
  487. } else if ip, err := netip.ParseAddr(v); err == nil {
  488. ipp = netip.AddrPortFrom(ip, 0)
  489. } else {
  490. var err error
  491. ipp, err = netip.ParseAddrPort(v)
  492. if err != nil {
  493. http.Error(w, "invalid 'addr' parameter", http.StatusBadRequest)
  494. return
  495. }
  496. }
  497. if ipp.IsValid() {
  498. n, u, ok = b.WhoIs(r.FormValue("proto"), ipp)
  499. }
  500. } else {
  501. http.Error(w, "missing 'addr' parameter", http.StatusBadRequest)
  502. return
  503. }
  504. if !ok {
  505. http.Error(w, "no match for IP:port", http.StatusNotFound)
  506. return
  507. }
  508. res := &apitype.WhoIsResponse{
  509. Node: n.AsStruct(), // always non-nil per WhoIsResponse contract
  510. UserProfile: &u, // always non-nil per WhoIsResponse contract
  511. }
  512. if n.Addresses().Len() > 0 {
  513. res.CapMap = b.PeerCaps(n.Addresses().At(0).Addr())
  514. }
  515. j, err := json.MarshalIndent(res, "", "\t")
  516. if err != nil {
  517. http.Error(w, "JSON encoding error", http.StatusInternalServerError)
  518. return
  519. }
  520. w.Header().Set("Content-Type", "application/json")
  521. w.Write(j)
  522. }
  523. func (h *Handler) serveGoroutines(w http.ResponseWriter, r *http.Request) {
  524. // Require write access out of paranoia that the goroutine dump
  525. // (at least its arguments) might contain something sensitive.
  526. if !h.PermitWrite {
  527. http.Error(w, "goroutine dump access denied", http.StatusForbidden)
  528. return
  529. }
  530. buf := make([]byte, 2<<20)
  531. buf = buf[:runtime.Stack(buf, true)]
  532. w.Header().Set("Content-Type", "text/plain")
  533. w.Write(buf)
  534. }
  535. // serveLogTap taps into the tailscaled/logtail server output and streams
  536. // it to the client.
  537. func (h *Handler) serveLogTap(w http.ResponseWriter, r *http.Request) {
  538. ctx := r.Context()
  539. // Require write access (~root) as the logs could contain something
  540. // sensitive.
  541. if !h.PermitWrite {
  542. http.Error(w, "logtap access denied", http.StatusForbidden)
  543. return
  544. }
  545. if r.Method != httpm.GET {
  546. http.Error(w, "GET required", http.StatusMethodNotAllowed)
  547. return
  548. }
  549. f, ok := w.(http.Flusher)
  550. if !ok {
  551. http.Error(w, "streaming unsupported", http.StatusInternalServerError)
  552. return
  553. }
  554. io.WriteString(w, `{"text":"[logtap connected]\n"}`+"\n")
  555. f.Flush()
  556. msgc := make(chan string, 16)
  557. unreg := logtail.RegisterLogTap(msgc)
  558. defer unreg()
  559. for {
  560. select {
  561. case <-ctx.Done():
  562. return
  563. case msg := <-msgc:
  564. io.WriteString(w, msg)
  565. f.Flush()
  566. }
  567. }
  568. }
  569. func (h *Handler) serveMetrics(w http.ResponseWriter, r *http.Request) {
  570. metricDebugMetricsCalls.Add(1)
  571. // Require write access out of paranoia that the metrics
  572. // might contain something sensitive.
  573. if !h.PermitWrite {
  574. http.Error(w, "metric access denied", http.StatusForbidden)
  575. return
  576. }
  577. w.Header().Set("Content-Type", "text/plain")
  578. clientmetric.WritePrometheusExpositionFormat(w)
  579. }
  580. // serveUserMetrics returns user-facing metrics in Prometheus text
  581. // exposition format.
  582. func (h *Handler) serveUserMetrics(w http.ResponseWriter, r *http.Request) {
  583. metricUserMetricsCalls.Add(1)
  584. h.b.UserMetricsRegistry().Handler(w, r)
  585. }
  586. func (h *Handler) serveDebug(w http.ResponseWriter, r *http.Request) {
  587. if !h.PermitWrite {
  588. http.Error(w, "debug access denied", http.StatusForbidden)
  589. return
  590. }
  591. if r.Method != httpm.POST {
  592. http.Error(w, "POST required", http.StatusMethodNotAllowed)
  593. return
  594. }
  595. // The action is normally in a POST form parameter, but
  596. // some actions (like "notify") want a full JSON body, so
  597. // permit some to have their action in a header.
  598. var action string
  599. switch v := r.Header.Get("Debug-Action"); v {
  600. case "notify":
  601. action = v
  602. default:
  603. action = r.FormValue("action")
  604. }
  605. var err error
  606. switch action {
  607. case "derp-set-homeless":
  608. h.b.MagicConn().SetHomeless(true)
  609. case "derp-unset-homeless":
  610. h.b.MagicConn().SetHomeless(false)
  611. case "rebind":
  612. err = h.b.DebugRebind()
  613. case "restun":
  614. err = h.b.DebugReSTUN()
  615. case "notify":
  616. var n ipn.Notify
  617. err = json.NewDecoder(r.Body).Decode(&n)
  618. if err != nil {
  619. break
  620. }
  621. h.b.DebugNotify(n)
  622. case "notify-last-netmap":
  623. h.b.DebugNotifyLastNetMap()
  624. case "break-tcp-conns":
  625. err = h.b.DebugBreakTCPConns()
  626. case "break-derp-conns":
  627. err = h.b.DebugBreakDERPConns()
  628. case "force-netmap-update":
  629. h.b.DebugForceNetmapUpdate()
  630. case "control-knobs":
  631. k := h.b.ControlKnobs()
  632. w.Header().Set("Content-Type", "application/json")
  633. err = json.NewEncoder(w).Encode(k.AsDebugJSON())
  634. if err == nil {
  635. return
  636. }
  637. case "pick-new-derp":
  638. err = h.b.DebugPickNewDERP()
  639. case "force-prefer-derp":
  640. var n int
  641. err = json.NewDecoder(r.Body).Decode(&n)
  642. if err != nil {
  643. break
  644. }
  645. h.b.DebugForcePreferDERP(n)
  646. case "peer-relay-servers":
  647. servers := h.b.DebugPeerRelayServers().Slice()
  648. slices.SortFunc(servers, func(a, b netip.Addr) int {
  649. return a.Compare(b)
  650. })
  651. err = json.NewEncoder(w).Encode(servers)
  652. if err == nil {
  653. return
  654. }
  655. case "":
  656. err = fmt.Errorf("missing parameter 'action'")
  657. default:
  658. err = fmt.Errorf("unknown action %q", action)
  659. }
  660. if err != nil {
  661. http.Error(w, err.Error(), http.StatusBadRequest)
  662. return
  663. }
  664. w.Header().Set("Content-Type", "text/plain")
  665. io.WriteString(w, "done\n")
  666. }
  667. func (h *Handler) serveDevSetStateStore(w http.ResponseWriter, r *http.Request) {
  668. if !h.PermitWrite {
  669. http.Error(w, "debug access denied", http.StatusForbidden)
  670. return
  671. }
  672. if r.Method != httpm.POST {
  673. http.Error(w, "POST required", http.StatusMethodNotAllowed)
  674. return
  675. }
  676. if err := h.b.SetDevStateStore(r.FormValue("key"), r.FormValue("value")); err != nil {
  677. http.Error(w, err.Error(), http.StatusInternalServerError)
  678. return
  679. }
  680. w.Header().Set("Content-Type", "text/plain")
  681. io.WriteString(w, "done\n")
  682. }
  683. func (h *Handler) serveDebugPacketFilterRules(w http.ResponseWriter, r *http.Request) {
  684. if !h.PermitWrite {
  685. http.Error(w, "debug access denied", http.StatusForbidden)
  686. return
  687. }
  688. nm := h.b.NetMap()
  689. if nm == nil {
  690. http.Error(w, "no netmap", http.StatusNotFound)
  691. return
  692. }
  693. w.Header().Set("Content-Type", "application/json")
  694. enc := json.NewEncoder(w)
  695. enc.SetIndent("", "\t")
  696. enc.Encode(nm.PacketFilterRules)
  697. }
  698. func (h *Handler) serveDebugPacketFilterMatches(w http.ResponseWriter, r *http.Request) {
  699. if !h.PermitWrite {
  700. http.Error(w, "debug access denied", http.StatusForbidden)
  701. return
  702. }
  703. nm := h.b.NetMap()
  704. if nm == nil {
  705. http.Error(w, "no netmap", http.StatusNotFound)
  706. return
  707. }
  708. w.Header().Set("Content-Type", "application/json")
  709. enc := json.NewEncoder(w)
  710. enc.SetIndent("", "\t")
  711. enc.Encode(nm.PacketFilter)
  712. }
  713. func (h *Handler) serveDebugPortmap(w http.ResponseWriter, r *http.Request) {
  714. if !h.PermitWrite {
  715. http.Error(w, "debug access denied", http.StatusForbidden)
  716. return
  717. }
  718. w.Header().Set("Content-Type", "text/plain")
  719. dur, err := time.ParseDuration(r.FormValue("duration"))
  720. if err != nil {
  721. http.Error(w, err.Error(), http.StatusBadRequest)
  722. return
  723. }
  724. gwSelf := r.FormValue("gateway_and_self")
  725. // Update portmapper debug flags
  726. debugKnobs := &portmapper.DebugKnobs{VerboseLogs: true}
  727. switch r.FormValue("type") {
  728. case "":
  729. case "pmp":
  730. debugKnobs.DisablePCP = true
  731. debugKnobs.DisableUPnP = true
  732. case "pcp":
  733. debugKnobs.DisablePMP = true
  734. debugKnobs.DisableUPnP = true
  735. case "upnp":
  736. debugKnobs.DisablePCP = true
  737. debugKnobs.DisablePMP = true
  738. default:
  739. http.Error(w, "unknown portmap debug type", http.StatusBadRequest)
  740. return
  741. }
  742. if defBool(r.FormValue("log_http"), false) {
  743. debugKnobs.LogHTTP = true
  744. }
  745. var (
  746. logLock sync.Mutex
  747. handlerDone bool
  748. )
  749. logf := func(format string, args ...any) {
  750. if !strings.HasSuffix(format, "\n") {
  751. format = format + "\n"
  752. }
  753. logLock.Lock()
  754. defer logLock.Unlock()
  755. // The portmapper can call this log function after the HTTP
  756. // handler returns, which is not allowed and can cause a panic.
  757. // If this happens, ignore the log lines since this typically
  758. // occurs due to a client disconnect.
  759. if handlerDone {
  760. return
  761. }
  762. // Write and flush each line to the client so that output is streamed
  763. fmt.Fprintf(w, format, args...)
  764. if f, ok := w.(http.Flusher); ok {
  765. f.Flush()
  766. }
  767. }
  768. defer func() {
  769. logLock.Lock()
  770. handlerDone = true
  771. logLock.Unlock()
  772. }()
  773. ctx, cancel := context.WithTimeout(r.Context(), dur)
  774. defer cancel()
  775. done := make(chan bool, 1)
  776. var c *portmapper.Client
  777. c = portmapper.NewClient(portmapper.Config{
  778. Logf: logger.WithPrefix(logf, "portmapper: "),
  779. NetMon: h.b.NetMon(),
  780. DebugKnobs: debugKnobs,
  781. ControlKnobs: h.b.ControlKnobs(),
  782. OnChange: func() {
  783. logf("portmapping changed.")
  784. logf("have mapping: %v", c.HaveMapping())
  785. if ext, ok := c.GetCachedMappingOrStartCreatingOne(); ok {
  786. logf("cb: mapping: %v", ext)
  787. select {
  788. case done <- true:
  789. default:
  790. }
  791. return
  792. }
  793. logf("cb: no mapping")
  794. },
  795. })
  796. defer c.Close()
  797. bus := eventbus.New()
  798. defer bus.Close()
  799. netMon, err := netmon.New(bus, logger.WithPrefix(logf, "monitor: "))
  800. if err != nil {
  801. logf("error creating monitor: %v", err)
  802. return
  803. }
  804. gatewayAndSelfIP := func() (gw, self netip.Addr, ok bool) {
  805. if a, b, ok := strings.Cut(gwSelf, "/"); ok {
  806. gw = netip.MustParseAddr(a)
  807. self = netip.MustParseAddr(b)
  808. return gw, self, true
  809. }
  810. return netMon.GatewayAndSelfIP()
  811. }
  812. c.SetGatewayLookupFunc(gatewayAndSelfIP)
  813. gw, selfIP, ok := gatewayAndSelfIP()
  814. if !ok {
  815. logf("no gateway or self IP; %v", netMon.InterfaceState())
  816. return
  817. }
  818. logf("gw=%v; self=%v", gw, selfIP)
  819. uc, err := net.ListenPacket("udp", "0.0.0.0:0")
  820. if err != nil {
  821. return
  822. }
  823. defer uc.Close()
  824. c.SetLocalPort(uint16(uc.LocalAddr().(*net.UDPAddr).Port))
  825. res, err := c.Probe(ctx)
  826. if err != nil {
  827. logf("error in Probe: %v", err)
  828. return
  829. }
  830. logf("Probe: %+v", res)
  831. if !res.PCP && !res.PMP && !res.UPnP {
  832. logf("no portmapping services available")
  833. return
  834. }
  835. if ext, ok := c.GetCachedMappingOrStartCreatingOne(); ok {
  836. logf("mapping: %v", ext)
  837. } else {
  838. logf("no mapping")
  839. }
  840. select {
  841. case <-done:
  842. case <-ctx.Done():
  843. if r.Context().Err() == nil {
  844. logf("serveDebugPortmap: context done: %v", ctx.Err())
  845. } else {
  846. h.logf("serveDebugPortmap: context done: %v", ctx.Err())
  847. }
  848. }
  849. }
  850. // EventError provides the JSON encoding of internal errors from event processing.
  851. type EventError struct {
  852. Error string
  853. }
  854. // serveDebugBusEvents taps into the tailscaled/utils/eventbus and streams
  855. // events to the client.
  856. func (h *Handler) serveDebugBusEvents(w http.ResponseWriter, r *http.Request) {
  857. // Require write access (~root) as the logs could contain something
  858. // sensitive.
  859. if !h.PermitWrite {
  860. http.Error(w, "event bus access denied", http.StatusForbidden)
  861. return
  862. }
  863. if r.Method != httpm.GET {
  864. http.Error(w, "GET required", http.StatusMethodNotAllowed)
  865. return
  866. }
  867. bus, ok := h.LocalBackend().Sys().Bus.GetOK()
  868. if !ok {
  869. http.Error(w, "event bus not running", http.StatusNoContent)
  870. return
  871. }
  872. f, ok := w.(http.Flusher)
  873. if !ok {
  874. http.Error(w, "streaming unsupported", http.StatusInternalServerError)
  875. return
  876. }
  877. io.WriteString(w, `{"Event":"[event listener connected]\n"}`+"\n")
  878. f.Flush()
  879. mon := bus.Debugger().WatchBus()
  880. defer mon.Close()
  881. i := 0
  882. for {
  883. select {
  884. case <-r.Context().Done():
  885. fmt.Fprintf(w, `{"Event":"[event listener closed]\n"}`)
  886. return
  887. case <-mon.Done():
  888. return
  889. case event := <-mon.Events():
  890. data := eventbus.DebugEvent{
  891. Count: i,
  892. Type: reflect.TypeOf(event.Event).String(),
  893. Event: event.Event,
  894. From: event.From.Name(),
  895. }
  896. for _, client := range event.To {
  897. data.To = append(data.To, client.Name())
  898. }
  899. if msg, err := json.Marshal(data); err != nil {
  900. data.Event = EventError{Error: fmt.Sprintf(
  901. "failed to marshal JSON for %T", event.Event,
  902. )}
  903. if errMsg, err := json.Marshal(data); err != nil {
  904. fmt.Fprintf(w,
  905. `{"Count": %d, "Event":"[ERROR] failed to marshal JSON for %T\n"}`,
  906. i, event.Event)
  907. } else {
  908. w.Write(errMsg)
  909. }
  910. } else {
  911. w.Write(msg)
  912. }
  913. f.Flush()
  914. i++
  915. }
  916. }
  917. }
  918. // serveEventBusGraph taps into the event bus and dumps out the active graph of
  919. // publishers and subscribers. It does not represent anything about the messages
  920. // exchanged.
  921. func (h *Handler) serveEventBusGraph(w http.ResponseWriter, r *http.Request) {
  922. if r.Method != httpm.GET {
  923. http.Error(w, "GET required", http.StatusMethodNotAllowed)
  924. return
  925. }
  926. bus, ok := h.LocalBackend().Sys().Bus.GetOK()
  927. if !ok {
  928. http.Error(w, "event bus not running", http.StatusPreconditionFailed)
  929. return
  930. }
  931. debugger := bus.Debugger()
  932. clients := debugger.Clients()
  933. graph := map[string]eventbus.DebugTopic{}
  934. for _, client := range clients {
  935. for _, pub := range debugger.PublishTypes(client) {
  936. topic, ok := graph[pub.Name()]
  937. if !ok {
  938. topic = eventbus.DebugTopic{Name: pub.Name()}
  939. }
  940. topic.Publisher = client.Name()
  941. graph[pub.Name()] = topic
  942. }
  943. for _, sub := range debugger.SubscribeTypes(client) {
  944. topic, ok := graph[sub.Name()]
  945. if !ok {
  946. topic = eventbus.DebugTopic{Name: sub.Name()}
  947. }
  948. topic.Subscribers = append(topic.Subscribers, client.Name())
  949. graph[sub.Name()] = topic
  950. }
  951. }
  952. // The top level map is not really needed for the client, convert to a list.
  953. topics := eventbus.DebugTopics{}
  954. for _, v := range graph {
  955. topics.Topics = append(topics.Topics, v)
  956. }
  957. w.Header().Set("Content-Type", "application/json")
  958. json.NewEncoder(w).Encode(topics)
  959. }
  960. func (h *Handler) serveComponentDebugLogging(w http.ResponseWriter, r *http.Request) {
  961. if !h.PermitWrite {
  962. http.Error(w, "debug access denied", http.StatusForbidden)
  963. return
  964. }
  965. component := r.FormValue("component")
  966. secs, _ := strconv.Atoi(r.FormValue("secs"))
  967. err := h.b.SetComponentDebugLogging(component, h.clock.Now().Add(time.Duration(secs)*time.Second))
  968. var res struct {
  969. Error string
  970. }
  971. if err != nil {
  972. res.Error = err.Error()
  973. }
  974. w.Header().Set("Content-Type", "application/json")
  975. json.NewEncoder(w).Encode(res)
  976. }
  977. func (h *Handler) serveDebugDialTypes(w http.ResponseWriter, r *http.Request) {
  978. if !h.PermitWrite {
  979. http.Error(w, "debug-dial-types access denied", http.StatusForbidden)
  980. return
  981. }
  982. if r.Method != httpm.POST {
  983. http.Error(w, "only POST allowed", http.StatusMethodNotAllowed)
  984. return
  985. }
  986. ip := r.FormValue("ip")
  987. port := r.FormValue("port")
  988. network := r.FormValue("network")
  989. addr := ip + ":" + port
  990. if _, err := netip.ParseAddrPort(addr); err != nil {
  991. w.WriteHeader(http.StatusBadRequest)
  992. fmt.Fprintf(w, "invalid address %q: %v", addr, err)
  993. return
  994. }
  995. ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
  996. defer cancel()
  997. var bareDialer net.Dialer
  998. dialer := h.b.Dialer()
  999. var peerDialer net.Dialer
  1000. peerDialer.Control = dialer.PeerDialControlFunc()
  1001. // Kick off a dial with each available dialer in parallel.
  1002. dialers := []struct {
  1003. name string
  1004. dial func(context.Context, string, string) (net.Conn, error)
  1005. }{
  1006. {"SystemDial", dialer.SystemDial},
  1007. {"UserDial", dialer.UserDial},
  1008. {"PeerDial", peerDialer.DialContext},
  1009. {"BareDial", bareDialer.DialContext},
  1010. }
  1011. type result struct {
  1012. name string
  1013. conn net.Conn
  1014. err error
  1015. }
  1016. results := make(chan result, len(dialers))
  1017. var wg sync.WaitGroup
  1018. for _, dialer := range dialers {
  1019. dialer := dialer // loop capture
  1020. wg.Add(1)
  1021. go func() {
  1022. defer wg.Done()
  1023. conn, err := dialer.dial(ctx, network, addr)
  1024. results <- result{dialer.name, conn, err}
  1025. }()
  1026. }
  1027. wg.Wait()
  1028. for range len(dialers) {
  1029. res := <-results
  1030. fmt.Fprintf(w, "[%s] connected=%v err=%v\n", res.name, res.conn != nil, res.err)
  1031. if res.conn != nil {
  1032. res.conn.Close()
  1033. }
  1034. }
  1035. }
  1036. // servePprofFunc is the implementation of Handler.servePprof, after auth,
  1037. // for platforms where we want to link it in.
  1038. var servePprofFunc func(http.ResponseWriter, *http.Request)
  1039. func (h *Handler) servePprof(w http.ResponseWriter, r *http.Request) {
  1040. // Require write access out of paranoia that the profile dump
  1041. // might contain something sensitive.
  1042. if !h.PermitWrite {
  1043. http.Error(w, "profile access denied", http.StatusForbidden)
  1044. return
  1045. }
  1046. if servePprofFunc == nil {
  1047. http.Error(w, "not implemented on this platform", http.StatusServiceUnavailable)
  1048. return
  1049. }
  1050. servePprofFunc(w, r)
  1051. }
  1052. // disconnectControl is the handler for local API /disconnect-control endpoint that shuts down control client, so that
  1053. // node no longer communicates with control. Doing this makes control consider this node inactive. This can be used
  1054. // before shutting down a replica of HA subnet router or app connector deployments to ensure that control tells the
  1055. // peers to switch over to another replica whilst still maintaining th existing peer connections.
  1056. func (h *Handler) disconnectControl(w http.ResponseWriter, r *http.Request) {
  1057. if !h.PermitWrite {
  1058. http.Error(w, "access denied", http.StatusForbidden)
  1059. return
  1060. }
  1061. if r.Method != httpm.POST {
  1062. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1063. return
  1064. }
  1065. h.b.DisconnectControl()
  1066. }
  1067. func (h *Handler) reloadConfig(w http.ResponseWriter, r *http.Request) {
  1068. if !h.PermitWrite {
  1069. http.Error(w, "access denied", http.StatusForbidden)
  1070. return
  1071. }
  1072. if r.Method != httpm.POST {
  1073. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1074. return
  1075. }
  1076. ok, err := h.b.ReloadConfig()
  1077. var res apitype.ReloadConfigResponse
  1078. res.Reloaded = ok
  1079. if err != nil {
  1080. res.Err = err.Error()
  1081. return
  1082. }
  1083. w.Header().Set("Content-Type", "application/json")
  1084. json.NewEncoder(w).Encode(&res)
  1085. }
  1086. func (h *Handler) serveResetAuth(w http.ResponseWriter, r *http.Request) {
  1087. if !h.PermitWrite {
  1088. http.Error(w, "reset-auth modify access denied", http.StatusForbidden)
  1089. return
  1090. }
  1091. if r.Method != httpm.POST {
  1092. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1093. return
  1094. }
  1095. if err := h.b.ResetAuth(); err != nil {
  1096. http.Error(w, "reset-auth failed: "+err.Error(), http.StatusInternalServerError)
  1097. return
  1098. }
  1099. w.WriteHeader(http.StatusNoContent)
  1100. }
  1101. func (h *Handler) serveServeConfig(w http.ResponseWriter, r *http.Request) {
  1102. switch r.Method {
  1103. case httpm.GET:
  1104. if !h.PermitRead {
  1105. http.Error(w, "serve config denied", http.StatusForbidden)
  1106. return
  1107. }
  1108. config := h.b.ServeConfig()
  1109. bts, err := json.Marshal(config)
  1110. if err != nil {
  1111. http.Error(w, "error encoding config: "+err.Error(), http.StatusInternalServerError)
  1112. return
  1113. }
  1114. sum := sha256.Sum256(bts)
  1115. etag := hex.EncodeToString(sum[:])
  1116. w.Header().Set("Etag", etag)
  1117. w.Header().Set("Content-Type", "application/json")
  1118. w.Write(bts)
  1119. case httpm.POST:
  1120. if !h.PermitWrite {
  1121. http.Error(w, "serve config denied", http.StatusForbidden)
  1122. return
  1123. }
  1124. configIn := new(ipn.ServeConfig)
  1125. if err := json.NewDecoder(r.Body).Decode(configIn); err != nil {
  1126. WriteErrorJSON(w, fmt.Errorf("decoding config: %w", err))
  1127. return
  1128. }
  1129. // require a local admin when setting a path handler
  1130. // TODO: roll-up this Windows-specific check into either PermitWrite
  1131. // or a global admin escalation check.
  1132. if err := authorizeServeConfigForGOOSAndUserContext(runtime.GOOS, configIn, h); err != nil {
  1133. http.Error(w, err.Error(), http.StatusUnauthorized)
  1134. return
  1135. }
  1136. etag := r.Header.Get("If-Match")
  1137. if err := h.b.SetServeConfig(configIn, etag); err != nil {
  1138. if errors.Is(err, ipnlocal.ErrETagMismatch) {
  1139. http.Error(w, err.Error(), http.StatusPreconditionFailed)
  1140. return
  1141. }
  1142. WriteErrorJSON(w, fmt.Errorf("updating config: %w", err))
  1143. return
  1144. }
  1145. w.WriteHeader(http.StatusOK)
  1146. default:
  1147. http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
  1148. }
  1149. }
  1150. func authorizeServeConfigForGOOSAndUserContext(goos string, configIn *ipn.ServeConfig, h *Handler) error {
  1151. switch goos {
  1152. case "windows", "linux", "darwin", "illumos", "solaris":
  1153. default:
  1154. return nil
  1155. }
  1156. // Only check for local admin on tailscaled-on-mac (based on "sudo"
  1157. // permissions). On sandboxed variants (MacSys and AppStore), tailscaled
  1158. // cannot serve files outside of the sandbox and this check is not
  1159. // relevant.
  1160. if goos == "darwin" && version.IsSandboxedMacOS() {
  1161. return nil
  1162. }
  1163. if !configIn.HasPathHandler() {
  1164. return nil
  1165. }
  1166. if h.Actor.IsLocalAdmin(h.b.OperatorUserID()) {
  1167. return nil
  1168. }
  1169. switch goos {
  1170. case "windows":
  1171. return errors.New("must be a Windows local admin to serve a path")
  1172. case "linux", "darwin", "illumos", "solaris":
  1173. return errors.New("must be root, or be an operator and able to run 'sudo tailscale' to serve a path")
  1174. default:
  1175. // We filter goos at the start of the func, this default case
  1176. // should never happen.
  1177. panic("unreachable")
  1178. }
  1179. }
  1180. func (h *Handler) serveCheckIPForwarding(w http.ResponseWriter, r *http.Request) {
  1181. if !h.PermitRead {
  1182. http.Error(w, "IP forwarding check access denied", http.StatusForbidden)
  1183. return
  1184. }
  1185. var warning string
  1186. if err := h.b.CheckIPForwarding(); err != nil {
  1187. warning = err.Error()
  1188. }
  1189. w.Header().Set("Content-Type", "application/json")
  1190. json.NewEncoder(w).Encode(struct {
  1191. Warning string
  1192. }{
  1193. Warning: warning,
  1194. })
  1195. }
  1196. func (h *Handler) serveCheckReversePathFiltering(w http.ResponseWriter, r *http.Request) {
  1197. if !h.PermitRead {
  1198. http.Error(w, "reverse path filtering check access denied", http.StatusForbidden)
  1199. return
  1200. }
  1201. var warning string
  1202. state := h.b.Sys().NetMon.Get().InterfaceState()
  1203. warn, err := netutil.CheckReversePathFiltering(state)
  1204. if err == nil && len(warn) > 0 {
  1205. var msg strings.Builder
  1206. msg.WriteString(healthmsg.WarnExitNodeUsage + ":\n")
  1207. for _, w := range warn {
  1208. msg.WriteString("- " + w + "\n")
  1209. }
  1210. msg.WriteString(healthmsg.DisableRPFilter)
  1211. warning = msg.String()
  1212. }
  1213. w.Header().Set("Content-Type", "application/json")
  1214. json.NewEncoder(w).Encode(struct {
  1215. Warning string
  1216. }{
  1217. Warning: warning,
  1218. })
  1219. }
  1220. func (h *Handler) serveCheckUDPGROForwarding(w http.ResponseWriter, r *http.Request) {
  1221. if !h.PermitRead {
  1222. http.Error(w, "UDP GRO forwarding check access denied", http.StatusForbidden)
  1223. return
  1224. }
  1225. var warning string
  1226. if err := h.b.CheckUDPGROForwarding(); err != nil {
  1227. warning = err.Error()
  1228. }
  1229. w.Header().Set("Content-Type", "application/json")
  1230. json.NewEncoder(w).Encode(struct {
  1231. Warning string
  1232. }{
  1233. Warning: warning,
  1234. })
  1235. }
  1236. func (h *Handler) serveSetUDPGROForwarding(w http.ResponseWriter, r *http.Request) {
  1237. if !h.PermitWrite {
  1238. http.Error(w, "UDP GRO forwarding set access denied", http.StatusForbidden)
  1239. return
  1240. }
  1241. var warning string
  1242. if err := h.b.SetUDPGROForwarding(); err != nil {
  1243. warning = err.Error()
  1244. }
  1245. w.Header().Set("Content-Type", "application/json")
  1246. json.NewEncoder(w).Encode(struct {
  1247. Warning string
  1248. }{
  1249. Warning: warning,
  1250. })
  1251. }
  1252. func (h *Handler) serveStatus(w http.ResponseWriter, r *http.Request) {
  1253. if !h.PermitRead {
  1254. http.Error(w, "status access denied", http.StatusForbidden)
  1255. return
  1256. }
  1257. w.Header().Set("Content-Type", "application/json")
  1258. var st *ipnstate.Status
  1259. if defBool(r.FormValue("peers"), true) {
  1260. st = h.b.Status()
  1261. } else {
  1262. st = h.b.StatusWithoutPeers()
  1263. }
  1264. e := json.NewEncoder(w)
  1265. e.SetIndent("", "\t")
  1266. e.Encode(st)
  1267. }
  1268. func (h *Handler) serveDebugPeerEndpointChanges(w http.ResponseWriter, r *http.Request) {
  1269. if !h.PermitRead {
  1270. http.Error(w, "status access denied", http.StatusForbidden)
  1271. return
  1272. }
  1273. ipStr := r.FormValue("ip")
  1274. if ipStr == "" {
  1275. http.Error(w, "missing 'ip' parameter", http.StatusBadRequest)
  1276. return
  1277. }
  1278. ip, err := netip.ParseAddr(ipStr)
  1279. if err != nil {
  1280. http.Error(w, "invalid IP", http.StatusBadRequest)
  1281. return
  1282. }
  1283. w.Header().Set("Content-Type", "application/json")
  1284. chs, err := h.b.GetPeerEndpointChanges(r.Context(), ip)
  1285. if err != nil {
  1286. http.Error(w, err.Error(), http.StatusInternalServerError)
  1287. return
  1288. }
  1289. e := json.NewEncoder(w)
  1290. e.SetIndent("", "\t")
  1291. e.Encode(chs)
  1292. }
  1293. // InUseOtherUserIPNStream reports whether r is a request for the watch-ipn-bus
  1294. // handler. If so, it writes an ipn.Notify InUseOtherUser message to the user
  1295. // and returns true. Otherwise it returns false, in which case it doesn't write
  1296. // to w.
  1297. //
  1298. // Unlike the regular watch-ipn-bus handler, this one doesn't block. The caller
  1299. // (in ipnserver.Server) provides the blocking until the connection is no longer
  1300. // in use.
  1301. func InUseOtherUserIPNStream(w http.ResponseWriter, r *http.Request, err error) (handled bool) {
  1302. if r.Method != httpm.GET || r.URL.Path != "/localapi/v0/watch-ipn-bus" {
  1303. return false
  1304. }
  1305. js, err := json.Marshal(&ipn.Notify{
  1306. Version: version.Long(),
  1307. State: ptr.To(ipn.InUseOtherUser),
  1308. ErrMessage: ptr.To(err.Error()),
  1309. })
  1310. if err != nil {
  1311. return false
  1312. }
  1313. js = append(js, '\n')
  1314. w.Header().Set("Content-Type", "application/json")
  1315. w.Write(js)
  1316. return true
  1317. }
  1318. func (h *Handler) serveWatchIPNBus(w http.ResponseWriter, r *http.Request) {
  1319. if !h.PermitRead {
  1320. http.Error(w, "watch ipn bus access denied", http.StatusForbidden)
  1321. return
  1322. }
  1323. f, ok := w.(http.Flusher)
  1324. if !ok {
  1325. http.Error(w, "not a flusher", http.StatusInternalServerError)
  1326. return
  1327. }
  1328. var mask ipn.NotifyWatchOpt
  1329. if s := r.FormValue("mask"); s != "" {
  1330. v, err := strconv.ParseUint(s, 10, 64)
  1331. if err != nil {
  1332. http.Error(w, "bad mask", http.StatusBadRequest)
  1333. return
  1334. }
  1335. mask = ipn.NotifyWatchOpt(v)
  1336. }
  1337. // Users with only read access must request private key filtering. If they
  1338. // don't filter out private keys, require write access.
  1339. if (mask & ipn.NotifyNoPrivateKeys) == 0 {
  1340. if !h.PermitWrite {
  1341. http.Error(w, "watch IPN bus access denied, must set ipn.NotifyNoPrivateKeys when not running as admin/root or operator", http.StatusForbidden)
  1342. return
  1343. }
  1344. }
  1345. w.Header().Set("Content-Type", "application/json")
  1346. ctx := r.Context()
  1347. enc := json.NewEncoder(w)
  1348. h.b.WatchNotificationsAs(ctx, h.Actor, mask, f.Flush, func(roNotify *ipn.Notify) (keepGoing bool) {
  1349. err := enc.Encode(roNotify)
  1350. if err != nil {
  1351. h.logf("json.Encode: %v", err)
  1352. return false
  1353. }
  1354. f.Flush()
  1355. return true
  1356. })
  1357. }
  1358. func (h *Handler) serveLoginInteractive(w http.ResponseWriter, r *http.Request) {
  1359. if !h.PermitWrite {
  1360. http.Error(w, "login access denied", http.StatusForbidden)
  1361. return
  1362. }
  1363. if r.Method != httpm.POST {
  1364. http.Error(w, "want POST", http.StatusBadRequest)
  1365. return
  1366. }
  1367. h.b.StartLoginInteractiveAs(r.Context(), h.Actor)
  1368. w.WriteHeader(http.StatusNoContent)
  1369. return
  1370. }
  1371. func (h *Handler) serveStart(w http.ResponseWriter, r *http.Request) {
  1372. if !h.PermitWrite {
  1373. http.Error(w, "access denied", http.StatusForbidden)
  1374. return
  1375. }
  1376. if r.Method != httpm.POST {
  1377. http.Error(w, "want POST", http.StatusBadRequest)
  1378. return
  1379. }
  1380. var o ipn.Options
  1381. if err := json.NewDecoder(r.Body).Decode(&o); err != nil {
  1382. http.Error(w, err.Error(), http.StatusBadRequest)
  1383. return
  1384. }
  1385. err := h.b.Start(o)
  1386. if err != nil {
  1387. // TODO(bradfitz): map error to a good HTTP error
  1388. http.Error(w, err.Error(), http.StatusInternalServerError)
  1389. return
  1390. }
  1391. w.WriteHeader(http.StatusNoContent)
  1392. }
  1393. func (h *Handler) serveLogout(w http.ResponseWriter, r *http.Request) {
  1394. if !h.PermitWrite {
  1395. http.Error(w, "logout access denied", http.StatusForbidden)
  1396. return
  1397. }
  1398. if r.Method != httpm.POST {
  1399. http.Error(w, "want POST", http.StatusBadRequest)
  1400. return
  1401. }
  1402. err := h.b.Logout(r.Context(), h.Actor)
  1403. if err == nil {
  1404. w.WriteHeader(http.StatusNoContent)
  1405. return
  1406. }
  1407. http.Error(w, err.Error(), http.StatusInternalServerError)
  1408. }
  1409. func (h *Handler) servePrefs(w http.ResponseWriter, r *http.Request) {
  1410. if !h.PermitRead {
  1411. http.Error(w, "prefs access denied", http.StatusForbidden)
  1412. return
  1413. }
  1414. var prefs ipn.PrefsView
  1415. switch r.Method {
  1416. case httpm.PATCH:
  1417. if !h.PermitWrite {
  1418. http.Error(w, "prefs write access denied", http.StatusForbidden)
  1419. return
  1420. }
  1421. mp := new(ipn.MaskedPrefs)
  1422. if err := json.NewDecoder(r.Body).Decode(mp); err != nil {
  1423. http.Error(w, err.Error(), http.StatusBadRequest)
  1424. return
  1425. }
  1426. if err := h.b.MaybeClearAppConnector(mp); err != nil {
  1427. w.Header().Set("Content-Type", "application/json")
  1428. w.WriteHeader(http.StatusInternalServerError)
  1429. json.NewEncoder(w).Encode(resJSON{Error: err.Error()})
  1430. return
  1431. }
  1432. var err error
  1433. prefs, err = h.b.EditPrefsAs(mp, h.Actor)
  1434. if err != nil {
  1435. w.Header().Set("Content-Type", "application/json")
  1436. w.WriteHeader(http.StatusBadRequest)
  1437. json.NewEncoder(w).Encode(resJSON{Error: err.Error()})
  1438. return
  1439. }
  1440. case httpm.GET, httpm.HEAD:
  1441. prefs = h.b.Prefs()
  1442. default:
  1443. http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
  1444. return
  1445. }
  1446. w.Header().Set("Content-Type", "application/json")
  1447. e := json.NewEncoder(w)
  1448. e.SetIndent("", "\t")
  1449. e.Encode(prefs)
  1450. }
  1451. func (h *Handler) servePolicy(w http.ResponseWriter, r *http.Request) {
  1452. if !h.PermitRead {
  1453. http.Error(w, "policy access denied", http.StatusForbidden)
  1454. return
  1455. }
  1456. suffix, ok := strings.CutPrefix(r.URL.EscapedPath(), "/localapi/v0/policy/")
  1457. if !ok {
  1458. http.Error(w, "misconfigured", http.StatusInternalServerError)
  1459. return
  1460. }
  1461. var scope setting.PolicyScope
  1462. if suffix == "" {
  1463. scope = setting.DefaultScope()
  1464. } else if err := scope.UnmarshalText([]byte(suffix)); err != nil {
  1465. http.Error(w, fmt.Sprintf("%q is not a valid scope", suffix), http.StatusBadRequest)
  1466. return
  1467. }
  1468. policy, err := rsop.PolicyFor(scope)
  1469. if err != nil {
  1470. http.Error(w, err.Error(), http.StatusInternalServerError)
  1471. return
  1472. }
  1473. var effectivePolicy *setting.Snapshot
  1474. switch r.Method {
  1475. case httpm.GET:
  1476. effectivePolicy = policy.Get()
  1477. case httpm.POST:
  1478. effectivePolicy, err = policy.Reload()
  1479. if err != nil {
  1480. http.Error(w, err.Error(), http.StatusInternalServerError)
  1481. return
  1482. }
  1483. default:
  1484. http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
  1485. return
  1486. }
  1487. w.Header().Set("Content-Type", "application/json")
  1488. e := json.NewEncoder(w)
  1489. e.SetIndent("", "\t")
  1490. e.Encode(effectivePolicy)
  1491. }
  1492. type resJSON struct {
  1493. Error string `json:",omitempty"`
  1494. }
  1495. func (h *Handler) serveCheckPrefs(w http.ResponseWriter, r *http.Request) {
  1496. if !h.PermitWrite {
  1497. http.Error(w, "checkprefs access denied", http.StatusForbidden)
  1498. return
  1499. }
  1500. if r.Method != httpm.POST {
  1501. http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
  1502. return
  1503. }
  1504. p := new(ipn.Prefs)
  1505. if err := json.NewDecoder(r.Body).Decode(p); err != nil {
  1506. http.Error(w, "invalid JSON body", http.StatusBadRequest)
  1507. return
  1508. }
  1509. err := h.b.CheckPrefs(p)
  1510. var res resJSON
  1511. if err != nil {
  1512. res.Error = err.Error()
  1513. }
  1514. w.Header().Set("Content-Type", "application/json")
  1515. json.NewEncoder(w).Encode(res)
  1516. }
  1517. // WriteErrorJSON writes a JSON object (with a single "error" string field) to w
  1518. // with the given error. If err is nil, "unexpected nil error" is used for the
  1519. // stringification instead.
  1520. func WriteErrorJSON(w http.ResponseWriter, err error) {
  1521. if err == nil {
  1522. err = errors.New("unexpected nil error")
  1523. }
  1524. w.Header().Set("Content-Type", "application/json")
  1525. w.WriteHeader(http.StatusInternalServerError)
  1526. type E struct {
  1527. Error string `json:"error"`
  1528. }
  1529. json.NewEncoder(w).Encode(E{err.Error()})
  1530. }
  1531. func (h *Handler) serveSetDNS(w http.ResponseWriter, r *http.Request) {
  1532. if !h.PermitWrite {
  1533. http.Error(w, "access denied", http.StatusForbidden)
  1534. return
  1535. }
  1536. if r.Method != httpm.POST {
  1537. http.Error(w, "want POST", http.StatusBadRequest)
  1538. return
  1539. }
  1540. ctx := r.Context()
  1541. err := h.b.SetDNS(ctx, r.FormValue("name"), r.FormValue("value"))
  1542. if err != nil {
  1543. WriteErrorJSON(w, err)
  1544. return
  1545. }
  1546. w.Header().Set("Content-Type", "application/json")
  1547. json.NewEncoder(w).Encode(struct{}{})
  1548. }
  1549. func (h *Handler) serveDERPMap(w http.ResponseWriter, r *http.Request) {
  1550. if r.Method != httpm.GET {
  1551. http.Error(w, "want GET", http.StatusBadRequest)
  1552. return
  1553. }
  1554. w.Header().Set("Content-Type", "application/json")
  1555. e := json.NewEncoder(w)
  1556. e.SetIndent("", "\t")
  1557. e.Encode(h.b.DERPMap())
  1558. }
  1559. // serveSetExpirySooner sets the expiry date on the current machine, specified
  1560. // by an `expiry` unix timestamp as POST or query param.
  1561. func (h *Handler) serveSetExpirySooner(w http.ResponseWriter, r *http.Request) {
  1562. if !h.PermitWrite {
  1563. http.Error(w, "access denied", http.StatusForbidden)
  1564. return
  1565. }
  1566. if r.Method != httpm.POST {
  1567. http.Error(w, "POST required", http.StatusMethodNotAllowed)
  1568. return
  1569. }
  1570. var expiryTime time.Time
  1571. if v := r.FormValue("expiry"); v != "" {
  1572. expiryInt, err := strconv.ParseInt(v, 10, 64)
  1573. if err != nil {
  1574. http.Error(w, "can't parse expiry time, expects a unix timestamp", http.StatusBadRequest)
  1575. return
  1576. }
  1577. expiryTime = time.Unix(expiryInt, 0)
  1578. } else {
  1579. http.Error(w, "missing 'expiry' parameter, a unix timestamp", http.StatusBadRequest)
  1580. return
  1581. }
  1582. err := h.b.SetExpirySooner(r.Context(), expiryTime)
  1583. if err != nil {
  1584. http.Error(w, err.Error(), http.StatusBadRequest)
  1585. return
  1586. }
  1587. w.Header().Set("Content-Type", "text/plain")
  1588. io.WriteString(w, "done\n")
  1589. }
  1590. func (h *Handler) servePing(w http.ResponseWriter, r *http.Request) {
  1591. ctx := r.Context()
  1592. if r.Method != httpm.POST {
  1593. http.Error(w, "want POST", http.StatusBadRequest)
  1594. return
  1595. }
  1596. ipStr := r.FormValue("ip")
  1597. if ipStr == "" {
  1598. http.Error(w, "missing 'ip' parameter", http.StatusBadRequest)
  1599. return
  1600. }
  1601. ip, err := netip.ParseAddr(ipStr)
  1602. if err != nil {
  1603. http.Error(w, "invalid IP", http.StatusBadRequest)
  1604. return
  1605. }
  1606. pingTypeStr := r.FormValue("type")
  1607. if pingTypeStr == "" {
  1608. http.Error(w, "missing 'type' parameter", http.StatusBadRequest)
  1609. return
  1610. }
  1611. size := 0
  1612. sizeStr := r.FormValue("size")
  1613. if sizeStr != "" {
  1614. size, err = strconv.Atoi(sizeStr)
  1615. if err != nil {
  1616. http.Error(w, "invalid 'size' parameter", http.StatusBadRequest)
  1617. return
  1618. }
  1619. if size != 0 && tailcfg.PingType(pingTypeStr) != tailcfg.PingDisco {
  1620. http.Error(w, "'size' parameter is only supported with disco pings", http.StatusBadRequest)
  1621. return
  1622. }
  1623. if size > magicsock.MaxDiscoPingSize {
  1624. http.Error(w, fmt.Sprintf("maximum value for 'size' is %v", magicsock.MaxDiscoPingSize), http.StatusBadRequest)
  1625. return
  1626. }
  1627. }
  1628. res, err := h.b.Ping(ctx, ip, tailcfg.PingType(pingTypeStr), size)
  1629. if err != nil {
  1630. WriteErrorJSON(w, err)
  1631. return
  1632. }
  1633. w.Header().Set("Content-Type", "application/json")
  1634. json.NewEncoder(w).Encode(res)
  1635. }
  1636. func (h *Handler) serveDial(w http.ResponseWriter, r *http.Request) {
  1637. if r.Method != httpm.POST {
  1638. http.Error(w, "POST required", http.StatusMethodNotAllowed)
  1639. return
  1640. }
  1641. const upgradeProto = "ts-dial"
  1642. if !strings.Contains(r.Header.Get("Connection"), "upgrade") ||
  1643. r.Header.Get("Upgrade") != upgradeProto {
  1644. http.Error(w, "bad ts-dial upgrade", http.StatusBadRequest)
  1645. return
  1646. }
  1647. hostStr, portStr := r.Header.Get("Dial-Host"), r.Header.Get("Dial-Port")
  1648. if hostStr == "" || portStr == "" {
  1649. http.Error(w, "missing Dial-Host or Dial-Port header", http.StatusBadRequest)
  1650. return
  1651. }
  1652. hijacker, ok := w.(http.Hijacker)
  1653. if !ok {
  1654. http.Error(w, "make request over HTTP/1", http.StatusBadRequest)
  1655. return
  1656. }
  1657. network := cmp.Or(r.Header.Get("Dial-Network"), "tcp")
  1658. addr := net.JoinHostPort(hostStr, portStr)
  1659. outConn, err := h.b.Dialer().UserDial(r.Context(), network, addr)
  1660. if err != nil {
  1661. http.Error(w, "dial failure: "+err.Error(), http.StatusBadGateway)
  1662. return
  1663. }
  1664. defer outConn.Close()
  1665. w.Header().Set("Upgrade", upgradeProto)
  1666. w.Header().Set("Connection", "upgrade")
  1667. w.WriteHeader(http.StatusSwitchingProtocols)
  1668. reqConn, brw, err := hijacker.Hijack()
  1669. if err != nil {
  1670. h.logf("localapi dial Hijack error: %v", err)
  1671. return
  1672. }
  1673. defer reqConn.Close()
  1674. if err := brw.Flush(); err != nil {
  1675. return
  1676. }
  1677. reqConn = netutil.NewDrainBufConn(reqConn, brw.Reader)
  1678. errc := make(chan error, 1)
  1679. go func() {
  1680. _, err := io.Copy(reqConn, outConn)
  1681. errc <- err
  1682. }()
  1683. go func() {
  1684. _, err := io.Copy(outConn, reqConn)
  1685. errc <- err
  1686. }()
  1687. <-errc
  1688. }
  1689. func (h *Handler) serveSetPushDeviceToken(w http.ResponseWriter, r *http.Request) {
  1690. if !h.PermitWrite {
  1691. http.Error(w, "set push device token access denied", http.StatusForbidden)
  1692. return
  1693. }
  1694. if r.Method != httpm.POST {
  1695. http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
  1696. return
  1697. }
  1698. var params apitype.SetPushDeviceTokenRequest
  1699. if err := json.NewDecoder(r.Body).Decode(&params); err != nil {
  1700. http.Error(w, "invalid JSON body", http.StatusBadRequest)
  1701. return
  1702. }
  1703. h.b.SetPushDeviceToken(params.PushDeviceToken)
  1704. w.WriteHeader(http.StatusOK)
  1705. }
  1706. func (h *Handler) serveHandlePushMessage(w http.ResponseWriter, r *http.Request) {
  1707. if !h.PermitWrite {
  1708. http.Error(w, "handle push message not allowed", http.StatusForbidden)
  1709. return
  1710. }
  1711. if r.Method != httpm.POST {
  1712. http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
  1713. return
  1714. }
  1715. var pushMessageBody map[string]any
  1716. if err := json.NewDecoder(r.Body).Decode(&pushMessageBody); err != nil {
  1717. http.Error(w, "failed to decode JSON body: "+err.Error(), http.StatusBadRequest)
  1718. return
  1719. }
  1720. // TODO(bradfitz): do something with pushMessageBody
  1721. h.logf("localapi: got push message: %v", logger.AsJSON(pushMessageBody))
  1722. w.WriteHeader(http.StatusNoContent)
  1723. }
  1724. func (h *Handler) serveUploadClientMetrics(w http.ResponseWriter, r *http.Request) {
  1725. if r.Method != httpm.POST {
  1726. http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
  1727. return
  1728. }
  1729. type clientMetricJSON struct {
  1730. Name string `json:"name"`
  1731. Type string `json:"type"` // one of "counter" or "gauge"
  1732. Value int `json:"value"` // amount to increment metric by
  1733. }
  1734. var clientMetrics []clientMetricJSON
  1735. if err := json.NewDecoder(r.Body).Decode(&clientMetrics); err != nil {
  1736. http.Error(w, "invalid JSON body", http.StatusBadRequest)
  1737. return
  1738. }
  1739. metricsMu.Lock()
  1740. defer metricsMu.Unlock()
  1741. for _, m := range clientMetrics {
  1742. if metric, ok := metrics[m.Name]; ok {
  1743. metric.Add(int64(m.Value))
  1744. } else {
  1745. if clientmetric.HasPublished(m.Name) {
  1746. http.Error(w, "Already have a metric named "+m.Name, http.StatusBadRequest)
  1747. return
  1748. }
  1749. var metric *clientmetric.Metric
  1750. switch m.Type {
  1751. case "counter":
  1752. metric = clientmetric.NewCounter(m.Name)
  1753. case "gauge":
  1754. metric = clientmetric.NewGauge(m.Name)
  1755. default:
  1756. http.Error(w, "Unknown metric type "+m.Type, http.StatusBadRequest)
  1757. return
  1758. }
  1759. metrics[m.Name] = metric
  1760. metric.Add(int64(m.Value))
  1761. }
  1762. }
  1763. w.Header().Set("Content-Type", "application/json")
  1764. json.NewEncoder(w).Encode(struct{}{})
  1765. }
  1766. func (h *Handler) serveTKAStatus(w http.ResponseWriter, r *http.Request) {
  1767. if !h.PermitRead {
  1768. http.Error(w, "lock status access denied", http.StatusForbidden)
  1769. return
  1770. }
  1771. if r.Method != httpm.GET {
  1772. http.Error(w, "use GET", http.StatusMethodNotAllowed)
  1773. return
  1774. }
  1775. j, err := json.MarshalIndent(h.b.NetworkLockStatus(), "", "\t")
  1776. if err != nil {
  1777. http.Error(w, "JSON encoding error", http.StatusInternalServerError)
  1778. return
  1779. }
  1780. w.Header().Set("Content-Type", "application/json")
  1781. w.Write(j)
  1782. }
  1783. func (h *Handler) serveSetGUIVisible(w http.ResponseWriter, r *http.Request) {
  1784. if r.Method != httpm.POST {
  1785. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1786. return
  1787. }
  1788. type setGUIVisibleRequest struct {
  1789. IsVisible bool // whether the Tailscale client UI is now presented to the user
  1790. SessionID string // the last SessionID sent to the client in ipn.Notify.SessionID
  1791. }
  1792. var req setGUIVisibleRequest
  1793. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  1794. http.Error(w, "invalid JSON body", http.StatusBadRequest)
  1795. return
  1796. }
  1797. // TODO(bradfitz): use `req.IsVisible == true` to flush netmap
  1798. w.WriteHeader(http.StatusOK)
  1799. }
  1800. func (h *Handler) serveSetUseExitNodeEnabled(w http.ResponseWriter, r *http.Request) {
  1801. if r.Method != httpm.POST {
  1802. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1803. return
  1804. }
  1805. if !h.PermitWrite {
  1806. http.Error(w, "access denied", http.StatusForbidden)
  1807. return
  1808. }
  1809. v, err := strconv.ParseBool(r.URL.Query().Get("enabled"))
  1810. if err != nil {
  1811. http.Error(w, "invalid 'enabled' parameter", http.StatusBadRequest)
  1812. return
  1813. }
  1814. prefs, err := h.b.SetUseExitNodeEnabled(h.Actor, v)
  1815. if err != nil {
  1816. http.Error(w, err.Error(), http.StatusInternalServerError)
  1817. return
  1818. }
  1819. w.Header().Set("Content-Type", "application/json")
  1820. e := json.NewEncoder(w)
  1821. e.SetIndent("", "\t")
  1822. e.Encode(prefs)
  1823. }
  1824. func (h *Handler) serveTKASign(w http.ResponseWriter, r *http.Request) {
  1825. if !h.PermitWrite {
  1826. http.Error(w, "lock sign access denied", http.StatusForbidden)
  1827. return
  1828. }
  1829. if r.Method != httpm.POST {
  1830. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1831. return
  1832. }
  1833. type signRequest struct {
  1834. NodeKey key.NodePublic
  1835. RotationPublic []byte
  1836. }
  1837. var req signRequest
  1838. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  1839. http.Error(w, "invalid JSON body", http.StatusBadRequest)
  1840. return
  1841. }
  1842. if err := h.b.NetworkLockSign(req.NodeKey, req.RotationPublic); err != nil {
  1843. http.Error(w, "signing failed: "+err.Error(), http.StatusInternalServerError)
  1844. return
  1845. }
  1846. w.WriteHeader(http.StatusOK)
  1847. }
  1848. func (h *Handler) serveTKAInit(w http.ResponseWriter, r *http.Request) {
  1849. if !h.PermitWrite {
  1850. http.Error(w, "lock init access denied", http.StatusForbidden)
  1851. return
  1852. }
  1853. if r.Method != httpm.POST {
  1854. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1855. return
  1856. }
  1857. type initRequest struct {
  1858. Keys []tka.Key
  1859. DisablementValues [][]byte
  1860. SupportDisablement []byte
  1861. }
  1862. var req initRequest
  1863. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  1864. http.Error(w, "invalid JSON body", http.StatusBadRequest)
  1865. return
  1866. }
  1867. if !h.b.NetworkLockAllowed() {
  1868. http.Error(w, "Tailnet Lock is not supported on your pricing plan", http.StatusForbidden)
  1869. return
  1870. }
  1871. if err := h.b.NetworkLockInit(req.Keys, req.DisablementValues, req.SupportDisablement); err != nil {
  1872. http.Error(w, "initialization failed: "+err.Error(), http.StatusInternalServerError)
  1873. return
  1874. }
  1875. j, err := json.MarshalIndent(h.b.NetworkLockStatus(), "", "\t")
  1876. if err != nil {
  1877. http.Error(w, "JSON encoding error", http.StatusInternalServerError)
  1878. return
  1879. }
  1880. w.Header().Set("Content-Type", "application/json")
  1881. w.Write(j)
  1882. }
  1883. func (h *Handler) serveTKAModify(w http.ResponseWriter, r *http.Request) {
  1884. if !h.PermitWrite {
  1885. http.Error(w, "network-lock modify access denied", http.StatusForbidden)
  1886. return
  1887. }
  1888. if r.Method != httpm.POST {
  1889. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1890. return
  1891. }
  1892. type modifyRequest struct {
  1893. AddKeys []tka.Key
  1894. RemoveKeys []tka.Key
  1895. }
  1896. var req modifyRequest
  1897. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  1898. http.Error(w, "invalid JSON body", http.StatusBadRequest)
  1899. return
  1900. }
  1901. if err := h.b.NetworkLockModify(req.AddKeys, req.RemoveKeys); err != nil {
  1902. http.Error(w, "network-lock modify failed: "+err.Error(), http.StatusInternalServerError)
  1903. return
  1904. }
  1905. w.WriteHeader(204)
  1906. }
  1907. func (h *Handler) serveTKAWrapPreauthKey(w http.ResponseWriter, r *http.Request) {
  1908. if !h.PermitWrite {
  1909. http.Error(w, "network-lock modify access denied", http.StatusForbidden)
  1910. return
  1911. }
  1912. if r.Method != httpm.POST {
  1913. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1914. return
  1915. }
  1916. type wrapRequest struct {
  1917. TSKey string
  1918. TKAKey string // key.NLPrivate.MarshalText
  1919. }
  1920. var req wrapRequest
  1921. if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 12*1024)).Decode(&req); err != nil {
  1922. http.Error(w, "invalid JSON body", http.StatusBadRequest)
  1923. return
  1924. }
  1925. var priv key.NLPrivate
  1926. if err := priv.UnmarshalText([]byte(req.TKAKey)); err != nil {
  1927. http.Error(w, "invalid JSON body", http.StatusBadRequest)
  1928. return
  1929. }
  1930. wrappedKey, err := h.b.NetworkLockWrapPreauthKey(req.TSKey, priv)
  1931. if err != nil {
  1932. http.Error(w, err.Error(), http.StatusInternalServerError)
  1933. return
  1934. }
  1935. w.WriteHeader(http.StatusOK)
  1936. w.Write([]byte(wrappedKey))
  1937. }
  1938. func (h *Handler) serveTKAVerifySigningDeeplink(w http.ResponseWriter, r *http.Request) {
  1939. if !h.PermitRead {
  1940. http.Error(w, "signing deeplink verification access denied", http.StatusForbidden)
  1941. return
  1942. }
  1943. if r.Method != httpm.POST {
  1944. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1945. return
  1946. }
  1947. type verifyRequest struct {
  1948. URL string
  1949. }
  1950. var req verifyRequest
  1951. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  1952. http.Error(w, "invalid JSON for verifyRequest body", http.StatusBadRequest)
  1953. return
  1954. }
  1955. res := h.b.NetworkLockVerifySigningDeeplink(req.URL)
  1956. j, err := json.MarshalIndent(res, "", "\t")
  1957. if err != nil {
  1958. http.Error(w, "JSON encoding error", http.StatusInternalServerError)
  1959. return
  1960. }
  1961. w.Header().Set("Content-Type", "application/json")
  1962. w.Write(j)
  1963. }
  1964. func (h *Handler) serveTKADisable(w http.ResponseWriter, r *http.Request) {
  1965. if !h.PermitWrite {
  1966. http.Error(w, "network-lock modify access denied", http.StatusForbidden)
  1967. return
  1968. }
  1969. if r.Method != httpm.POST {
  1970. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1971. return
  1972. }
  1973. body := io.LimitReader(r.Body, 1024*1024)
  1974. secret, err := io.ReadAll(body)
  1975. if err != nil {
  1976. http.Error(w, "reading secret", http.StatusBadRequest)
  1977. return
  1978. }
  1979. if err := h.b.NetworkLockDisable(secret); err != nil {
  1980. http.Error(w, "network-lock disable failed: "+err.Error(), http.StatusBadRequest)
  1981. return
  1982. }
  1983. w.WriteHeader(http.StatusOK)
  1984. }
  1985. func (h *Handler) serveTKALocalDisable(w http.ResponseWriter, r *http.Request) {
  1986. if !h.PermitWrite {
  1987. http.Error(w, "network-lock modify access denied", http.StatusForbidden)
  1988. return
  1989. }
  1990. if r.Method != httpm.POST {
  1991. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  1992. return
  1993. }
  1994. // Require a JSON stanza for the body as an additional CSRF protection.
  1995. var req struct{}
  1996. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  1997. http.Error(w, "invalid JSON body", http.StatusBadRequest)
  1998. return
  1999. }
  2000. if err := h.b.NetworkLockForceLocalDisable(); err != nil {
  2001. http.Error(w, "network-lock local disable failed: "+err.Error(), http.StatusBadRequest)
  2002. return
  2003. }
  2004. w.WriteHeader(http.StatusOK)
  2005. }
  2006. func (h *Handler) serveTKALog(w http.ResponseWriter, r *http.Request) {
  2007. if r.Method != httpm.GET {
  2008. http.Error(w, "use GET", http.StatusMethodNotAllowed)
  2009. return
  2010. }
  2011. limit := 50
  2012. if limitStr := r.FormValue("limit"); limitStr != "" {
  2013. l, err := strconv.Atoi(limitStr)
  2014. if err != nil {
  2015. http.Error(w, "parsing 'limit' parameter: "+err.Error(), http.StatusBadRequest)
  2016. return
  2017. }
  2018. limit = int(l)
  2019. }
  2020. updates, err := h.b.NetworkLockLog(limit)
  2021. if err != nil {
  2022. http.Error(w, "reading log failed: "+err.Error(), http.StatusInternalServerError)
  2023. return
  2024. }
  2025. j, err := json.MarshalIndent(updates, "", "\t")
  2026. if err != nil {
  2027. http.Error(w, "JSON encoding error", http.StatusInternalServerError)
  2028. return
  2029. }
  2030. w.Header().Set("Content-Type", "application/json")
  2031. w.Write(j)
  2032. }
  2033. func (h *Handler) serveTKAAffectedSigs(w http.ResponseWriter, r *http.Request) {
  2034. if r.Method != httpm.POST {
  2035. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  2036. return
  2037. }
  2038. keyID, err := io.ReadAll(http.MaxBytesReader(w, r.Body, 2048))
  2039. if err != nil {
  2040. http.Error(w, "reading body", http.StatusBadRequest)
  2041. return
  2042. }
  2043. sigs, err := h.b.NetworkLockAffectedSigs(keyID)
  2044. if err != nil {
  2045. http.Error(w, err.Error(), http.StatusInternalServerError)
  2046. return
  2047. }
  2048. j, err := json.MarshalIndent(sigs, "", "\t")
  2049. if err != nil {
  2050. http.Error(w, "JSON encoding error", http.StatusInternalServerError)
  2051. return
  2052. }
  2053. w.Header().Set("Content-Type", "application/json")
  2054. w.Write(j)
  2055. }
  2056. func (h *Handler) serveTKAGenerateRecoveryAUM(w http.ResponseWriter, r *http.Request) {
  2057. if !h.PermitWrite {
  2058. http.Error(w, "access denied", http.StatusForbidden)
  2059. return
  2060. }
  2061. if r.Method != httpm.POST {
  2062. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  2063. return
  2064. }
  2065. type verifyRequest struct {
  2066. Keys []tkatype.KeyID
  2067. ForkFrom string
  2068. }
  2069. var req verifyRequest
  2070. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  2071. http.Error(w, "invalid JSON for verifyRequest body", http.StatusBadRequest)
  2072. return
  2073. }
  2074. var forkFrom tka.AUMHash
  2075. if req.ForkFrom != "" {
  2076. if err := forkFrom.UnmarshalText([]byte(req.ForkFrom)); err != nil {
  2077. http.Error(w, "decoding fork-from: "+err.Error(), http.StatusBadRequest)
  2078. return
  2079. }
  2080. }
  2081. res, err := h.b.NetworkLockGenerateRecoveryAUM(req.Keys, forkFrom)
  2082. if err != nil {
  2083. http.Error(w, err.Error(), http.StatusInternalServerError)
  2084. return
  2085. }
  2086. w.Header().Set("Content-Type", "application/octet-stream")
  2087. w.Write(res.Serialize())
  2088. }
  2089. func (h *Handler) serveTKACosignRecoveryAUM(w http.ResponseWriter, r *http.Request) {
  2090. if !h.PermitWrite {
  2091. http.Error(w, "access denied", http.StatusForbidden)
  2092. return
  2093. }
  2094. if r.Method != httpm.POST {
  2095. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  2096. return
  2097. }
  2098. body := io.LimitReader(r.Body, 1024*1024)
  2099. aumBytes, err := io.ReadAll(body)
  2100. if err != nil {
  2101. http.Error(w, "reading AUM", http.StatusBadRequest)
  2102. return
  2103. }
  2104. var aum tka.AUM
  2105. if err := aum.Unserialize(aumBytes); err != nil {
  2106. http.Error(w, "decoding AUM", http.StatusBadRequest)
  2107. return
  2108. }
  2109. res, err := h.b.NetworkLockCosignRecoveryAUM(&aum)
  2110. if err != nil {
  2111. http.Error(w, err.Error(), http.StatusInternalServerError)
  2112. return
  2113. }
  2114. w.Header().Set("Content-Type", "application/octet-stream")
  2115. w.Write(res.Serialize())
  2116. }
  2117. func (h *Handler) serveTKASubmitRecoveryAUM(w http.ResponseWriter, r *http.Request) {
  2118. if !h.PermitWrite {
  2119. http.Error(w, "access denied", http.StatusForbidden)
  2120. return
  2121. }
  2122. if r.Method != httpm.POST {
  2123. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  2124. return
  2125. }
  2126. body := io.LimitReader(r.Body, 1024*1024)
  2127. aumBytes, err := io.ReadAll(body)
  2128. if err != nil {
  2129. http.Error(w, "reading AUM", http.StatusBadRequest)
  2130. return
  2131. }
  2132. var aum tka.AUM
  2133. if err := aum.Unserialize(aumBytes); err != nil {
  2134. http.Error(w, "decoding AUM", http.StatusBadRequest)
  2135. return
  2136. }
  2137. if err := h.b.NetworkLockSubmitRecoveryAUM(&aum); err != nil {
  2138. http.Error(w, err.Error(), http.StatusInternalServerError)
  2139. return
  2140. }
  2141. w.WriteHeader(http.StatusOK)
  2142. }
  2143. // serveProfiles serves profile switching-related endpoints. Supported methods
  2144. // and paths are:
  2145. // - GET /profiles/: list all profiles (JSON-encoded array of ipn.LoginProfiles)
  2146. // - PUT /profiles/: add new profile (no response). A separate
  2147. // StartLoginInteractive() is needed to populate and persist the new profile.
  2148. // - GET /profiles/current: current profile (JSON-ecoded ipn.LoginProfile)
  2149. // - GET /profiles/<id>: output profile (JSON-ecoded ipn.LoginProfile)
  2150. // - POST /profiles/<id>: switch to profile (no response)
  2151. // - DELETE /profiles/<id>: delete profile (no response)
  2152. func (h *Handler) serveProfiles(w http.ResponseWriter, r *http.Request) {
  2153. if !h.PermitWrite {
  2154. http.Error(w, "profiles access denied", http.StatusForbidden)
  2155. return
  2156. }
  2157. suffix, ok := strings.CutPrefix(r.URL.EscapedPath(), "/localapi/v0/profiles/")
  2158. if !ok {
  2159. http.Error(w, "misconfigured", http.StatusInternalServerError)
  2160. return
  2161. }
  2162. if suffix == "" {
  2163. switch r.Method {
  2164. case httpm.GET:
  2165. w.Header().Set("Content-Type", "application/json")
  2166. json.NewEncoder(w).Encode(h.b.ListProfiles())
  2167. case httpm.PUT:
  2168. err := h.b.NewProfile()
  2169. if err != nil {
  2170. http.Error(w, err.Error(), http.StatusInternalServerError)
  2171. return
  2172. }
  2173. w.WriteHeader(http.StatusCreated)
  2174. default:
  2175. http.Error(w, "use GET or PUT", http.StatusMethodNotAllowed)
  2176. }
  2177. return
  2178. }
  2179. suffix, err := url.PathUnescape(suffix)
  2180. if err != nil {
  2181. http.Error(w, "bad profile ID", http.StatusBadRequest)
  2182. return
  2183. }
  2184. if suffix == "current" {
  2185. switch r.Method {
  2186. case httpm.GET:
  2187. w.Header().Set("Content-Type", "application/json")
  2188. json.NewEncoder(w).Encode(h.b.CurrentProfile())
  2189. default:
  2190. http.Error(w, "use GET", http.StatusMethodNotAllowed)
  2191. }
  2192. return
  2193. }
  2194. profileID := ipn.ProfileID(suffix)
  2195. switch r.Method {
  2196. case httpm.GET:
  2197. profiles := h.b.ListProfiles()
  2198. profileIndex := slices.IndexFunc(profiles, func(p ipn.LoginProfileView) bool {
  2199. return p.ID() == profileID
  2200. })
  2201. if profileIndex == -1 {
  2202. http.Error(w, "Profile not found", http.StatusNotFound)
  2203. return
  2204. }
  2205. w.Header().Set("Content-Type", "application/json")
  2206. json.NewEncoder(w).Encode(profiles[profileIndex])
  2207. case httpm.POST:
  2208. err := h.b.SwitchProfile(profileID)
  2209. if err != nil {
  2210. http.Error(w, err.Error(), http.StatusInternalServerError)
  2211. return
  2212. }
  2213. w.WriteHeader(http.StatusNoContent)
  2214. case httpm.DELETE:
  2215. err := h.b.DeleteProfile(profileID)
  2216. if err != nil {
  2217. http.Error(w, err.Error(), http.StatusInternalServerError)
  2218. return
  2219. }
  2220. w.WriteHeader(http.StatusNoContent)
  2221. default:
  2222. http.Error(w, "use POST or DELETE", http.StatusMethodNotAllowed)
  2223. }
  2224. }
  2225. // serveQueryFeature makes a request to the "/machine/feature/query"
  2226. // Noise endpoint to get instructions on how to enable a feature, such as
  2227. // Funnel, for the node's tailnet.
  2228. //
  2229. // This request itself does not directly enable the feature on behalf of
  2230. // the node, but rather returns information that can be presented to the
  2231. // acting user about where/how to enable the feature. If relevant, this
  2232. // includes a control URL the user can visit to explicitly consent to
  2233. // using the feature.
  2234. //
  2235. // See tailcfg.QueryFeatureResponse for full response structure.
  2236. func (h *Handler) serveQueryFeature(w http.ResponseWriter, r *http.Request) {
  2237. feature := r.FormValue("feature")
  2238. switch {
  2239. case !h.PermitRead:
  2240. http.Error(w, "access denied", http.StatusForbidden)
  2241. return
  2242. case r.Method != httpm.POST:
  2243. http.Error(w, "use POST", http.StatusMethodNotAllowed)
  2244. return
  2245. case feature == "":
  2246. http.Error(w, "missing feature", http.StatusInternalServerError)
  2247. return
  2248. }
  2249. nm := h.b.NetMap()
  2250. if nm == nil {
  2251. http.Error(w, "no netmap", http.StatusServiceUnavailable)
  2252. return
  2253. }
  2254. b, err := json.Marshal(&tailcfg.QueryFeatureRequest{
  2255. NodeKey: nm.NodeKey,
  2256. Feature: feature,
  2257. })
  2258. if err != nil {
  2259. http.Error(w, err.Error(), http.StatusInternalServerError)
  2260. return
  2261. }
  2262. req, err := http.NewRequestWithContext(r.Context(),
  2263. httpm.POST, "https://unused/machine/feature/query", bytes.NewReader(b))
  2264. if err != nil {
  2265. http.Error(w, err.Error(), http.StatusInternalServerError)
  2266. return
  2267. }
  2268. resp, err := h.b.DoNoiseRequest(req)
  2269. if err != nil {
  2270. http.Error(w, err.Error(), http.StatusInternalServerError)
  2271. return
  2272. }
  2273. defer resp.Body.Close()
  2274. w.Header().Set("Content-Type", "application/json")
  2275. w.WriteHeader(resp.StatusCode)
  2276. if _, err := io.Copy(w, resp.Body); err != nil {
  2277. http.Error(w, err.Error(), http.StatusInternalServerError)
  2278. return
  2279. }
  2280. }
  2281. func defBool(a string, def bool) bool {
  2282. if a == "" {
  2283. return def
  2284. }
  2285. v, err := strconv.ParseBool(a)
  2286. if err != nil {
  2287. return def
  2288. }
  2289. return v
  2290. }
  2291. func (h *Handler) serveDebugLog(w http.ResponseWriter, r *http.Request) {
  2292. if !h.PermitRead {
  2293. http.Error(w, "debug-log access denied", http.StatusForbidden)
  2294. return
  2295. }
  2296. if r.Method != httpm.POST {
  2297. http.Error(w, "only POST allowed", http.StatusMethodNotAllowed)
  2298. return
  2299. }
  2300. defer h.b.TryFlushLogs() // kick off upload after we're done logging
  2301. type logRequestJSON struct {
  2302. Lines []string
  2303. Prefix string
  2304. }
  2305. var logRequest logRequestJSON
  2306. if err := json.NewDecoder(r.Body).Decode(&logRequest); err != nil {
  2307. http.Error(w, "invalid JSON body", http.StatusBadRequest)
  2308. return
  2309. }
  2310. prefix := logRequest.Prefix
  2311. if prefix == "" {
  2312. prefix = "debug-log"
  2313. }
  2314. logf := logger.WithPrefix(h.logf, prefix+": ")
  2315. // We can write logs too fast for logtail to handle, even when
  2316. // opting-out of rate limits. Limit ourselves to at most one message
  2317. // per 20ms and a burst of 60 log lines, which should be fast enough to
  2318. // not block for too long but slow enough that we can upload all lines.
  2319. logf = logger.SlowLoggerWithClock(r.Context(), logf, 20*time.Millisecond, 60, h.clock.Now)
  2320. for _, line := range logRequest.Lines {
  2321. logf("%s", line)
  2322. }
  2323. w.WriteHeader(http.StatusNoContent)
  2324. }
  2325. // serveUpdateCheck returns the ClientVersion from Status, which contains
  2326. // information on whether an update is available, and if so, what version,
  2327. // *if* we support auto-updates on this platform. If we don't, this endpoint
  2328. // always returns a ClientVersion saying we're running the newest version.
  2329. // Effectively, it tells us whether serveUpdateInstall will be able to install
  2330. // an update for us.
  2331. func (h *Handler) serveUpdateCheck(w http.ResponseWriter, r *http.Request) {
  2332. if r.Method != httpm.GET {
  2333. http.Error(w, "only GET allowed", http.StatusMethodNotAllowed)
  2334. return
  2335. }
  2336. if !clientupdate.CanAutoUpdate() {
  2337. // if we don't support auto-update, just say that we're up to date
  2338. json.NewEncoder(w).Encode(tailcfg.ClientVersion{RunningLatest: true})
  2339. return
  2340. }
  2341. cv := h.b.StatusWithoutPeers().ClientVersion
  2342. // ipnstate.Status documentation notes that ClientVersion may be nil on some
  2343. // platforms where this information is unavailable. In that case, return a
  2344. // ClientVersion that says we're up to date, since we have no information on
  2345. // whether an update is possible.
  2346. if cv == nil {
  2347. cv = &tailcfg.ClientVersion{RunningLatest: true}
  2348. }
  2349. json.NewEncoder(w).Encode(cv)
  2350. }
  2351. // serveUpdateInstall sends a request to the LocalBackend to start a Tailscale
  2352. // self-update. A successful response does not indicate whether the update
  2353. // succeeded, only that the request was accepted. Clients should use
  2354. // serveUpdateProgress after pinging this endpoint to check how the update is
  2355. // going.
  2356. func (h *Handler) serveUpdateInstall(w http.ResponseWriter, r *http.Request) {
  2357. if r.Method != httpm.POST {
  2358. http.Error(w, "only POST allowed", http.StatusMethodNotAllowed)
  2359. return
  2360. }
  2361. w.WriteHeader(http.StatusAccepted)
  2362. go h.b.DoSelfUpdate()
  2363. }
  2364. // serveUpdateProgress returns the status of an in-progress Tailscale self-update.
  2365. // This is provided as a slice of ipnstate.UpdateProgress structs with various
  2366. // log messages in order from oldest to newest. If an update is not in progress,
  2367. // the returned slice will be empty.
  2368. func (h *Handler) serveUpdateProgress(w http.ResponseWriter, r *http.Request) {
  2369. if r.Method != httpm.GET {
  2370. http.Error(w, "only GET allowed", http.StatusMethodNotAllowed)
  2371. return
  2372. }
  2373. ups := h.b.GetSelfUpdateProgress()
  2374. json.NewEncoder(w).Encode(ups)
  2375. }
  2376. // serveDNSOSConfig serves the current system DNS configuration as a JSON object, if
  2377. // supported by the OS.
  2378. func (h *Handler) serveDNSOSConfig(w http.ResponseWriter, r *http.Request) {
  2379. if r.Method != httpm.GET {
  2380. http.Error(w, "only GET allowed", http.StatusMethodNotAllowed)
  2381. return
  2382. }
  2383. // Require write access for privacy reasons.
  2384. if !h.PermitWrite {
  2385. http.Error(w, "dns-osconfig dump access denied", http.StatusForbidden)
  2386. return
  2387. }
  2388. bCfg, err := h.b.GetDNSOSConfig()
  2389. if err != nil {
  2390. http.Error(w, err.Error(), http.StatusInternalServerError)
  2391. return
  2392. }
  2393. w.Header().Set("Content-Type", "application/json")
  2394. nameservers := make([]string, 0, len(bCfg.Nameservers))
  2395. for _, ns := range bCfg.Nameservers {
  2396. nameservers = append(nameservers, ns.String())
  2397. }
  2398. searchDomains := make([]string, 0, len(bCfg.SearchDomains))
  2399. for _, sd := range bCfg.SearchDomains {
  2400. searchDomains = append(searchDomains, sd.WithoutTrailingDot())
  2401. }
  2402. matchDomains := make([]string, 0, len(bCfg.MatchDomains))
  2403. for _, md := range bCfg.MatchDomains {
  2404. matchDomains = append(matchDomains, md.WithoutTrailingDot())
  2405. }
  2406. response := apitype.DNSOSConfig{
  2407. Nameservers: nameservers,
  2408. SearchDomains: searchDomains,
  2409. MatchDomains: matchDomains,
  2410. }
  2411. json.NewEncoder(w).Encode(response)
  2412. }
  2413. // serveDNSQuery provides the ability to perform DNS queries using the internal
  2414. // DNS forwarder. This is useful for debugging and testing purposes.
  2415. // URL parameters:
  2416. // - name: the domain name to query
  2417. // - type: the DNS record type to query as a number (default if empty: A = '1')
  2418. //
  2419. // The response if successful is a DNSQueryResponse JSON object.
  2420. func (h *Handler) serveDNSQuery(w http.ResponseWriter, r *http.Request) {
  2421. if r.Method != httpm.GET {
  2422. http.Error(w, "only GET allowed", http.StatusMethodNotAllowed)
  2423. return
  2424. }
  2425. // Require write access for privacy reasons.
  2426. if !h.PermitWrite {
  2427. http.Error(w, "dns-query access denied", http.StatusForbidden)
  2428. return
  2429. }
  2430. q := r.URL.Query()
  2431. name := q.Get("name")
  2432. queryType := q.Get("type")
  2433. qt := dnsmessage.TypeA
  2434. if queryType != "" {
  2435. t, err := dnstype.DNSMessageTypeForString(queryType)
  2436. if err != nil {
  2437. http.Error(w, err.Error(), http.StatusBadRequest)
  2438. return
  2439. }
  2440. qt = t
  2441. }
  2442. res, rrs, err := h.b.QueryDNS(name, qt)
  2443. if err != nil {
  2444. http.Error(w, err.Error(), http.StatusInternalServerError)
  2445. return
  2446. }
  2447. w.Header().Set("Content-Type", "application/json")
  2448. json.NewEncoder(w).Encode(&apitype.DNSQueryResponse{
  2449. Bytes: res,
  2450. Resolvers: rrs,
  2451. })
  2452. }
  2453. // serveDriveServerAddr handles updates of the Taildrive file server address.
  2454. func (h *Handler) serveDriveServerAddr(w http.ResponseWriter, r *http.Request) {
  2455. if r.Method != httpm.PUT {
  2456. http.Error(w, "only PUT allowed", http.StatusMethodNotAllowed)
  2457. return
  2458. }
  2459. b, err := io.ReadAll(r.Body)
  2460. if err != nil {
  2461. http.Error(w, err.Error(), http.StatusBadRequest)
  2462. return
  2463. }
  2464. h.b.DriveSetServerAddr(string(b))
  2465. w.WriteHeader(http.StatusCreated)
  2466. }
  2467. // serveShares handles the management of Taildrive shares.
  2468. //
  2469. // PUT - adds or updates an existing share
  2470. // DELETE - removes a share
  2471. // GET - gets a list of all shares, sorted by name
  2472. // POST - renames an existing share
  2473. func (h *Handler) serveShares(w http.ResponseWriter, r *http.Request) {
  2474. if !h.b.DriveSharingEnabled() {
  2475. http.Error(w, `taildrive sharing not enabled, please add the attribute "drive:share" to this node in your ACLs' "nodeAttrs" section`, http.StatusForbidden)
  2476. return
  2477. }
  2478. switch r.Method {
  2479. case httpm.PUT:
  2480. var share drive.Share
  2481. err := json.NewDecoder(r.Body).Decode(&share)
  2482. if err != nil {
  2483. http.Error(w, err.Error(), http.StatusBadRequest)
  2484. return
  2485. }
  2486. share.Path = path.Clean(share.Path)
  2487. fi, err := os.Stat(share.Path)
  2488. if err != nil {
  2489. http.Error(w, err.Error(), http.StatusBadRequest)
  2490. return
  2491. }
  2492. if !fi.IsDir() {
  2493. http.Error(w, "not a directory", http.StatusBadRequest)
  2494. return
  2495. }
  2496. if drive.AllowShareAs() {
  2497. // share as the connected user
  2498. username, err := h.Actor.Username()
  2499. if err != nil {
  2500. http.Error(w, err.Error(), http.StatusInternalServerError)
  2501. return
  2502. }
  2503. share.As = username
  2504. }
  2505. err = h.b.DriveSetShare(&share)
  2506. if err != nil {
  2507. if errors.Is(err, drive.ErrInvalidShareName) {
  2508. http.Error(w, "invalid share name", http.StatusBadRequest)
  2509. return
  2510. }
  2511. http.Error(w, err.Error(), http.StatusInternalServerError)
  2512. return
  2513. }
  2514. w.WriteHeader(http.StatusCreated)
  2515. case httpm.DELETE:
  2516. b, err := io.ReadAll(r.Body)
  2517. if err != nil {
  2518. http.Error(w, err.Error(), http.StatusBadRequest)
  2519. return
  2520. }
  2521. err = h.b.DriveRemoveShare(string(b))
  2522. if err != nil {
  2523. if os.IsNotExist(err) {
  2524. http.Error(w, "share not found", http.StatusNotFound)
  2525. return
  2526. }
  2527. http.Error(w, err.Error(), http.StatusInternalServerError)
  2528. return
  2529. }
  2530. w.WriteHeader(http.StatusNoContent)
  2531. case httpm.POST:
  2532. var names [2]string
  2533. err := json.NewDecoder(r.Body).Decode(&names)
  2534. if err != nil {
  2535. http.Error(w, err.Error(), http.StatusBadRequest)
  2536. return
  2537. }
  2538. err = h.b.DriveRenameShare(names[0], names[1])
  2539. if err != nil {
  2540. if os.IsNotExist(err) {
  2541. http.Error(w, "share not found", http.StatusNotFound)
  2542. return
  2543. }
  2544. if os.IsExist(err) {
  2545. http.Error(w, "share name already used", http.StatusBadRequest)
  2546. return
  2547. }
  2548. if errors.Is(err, drive.ErrInvalidShareName) {
  2549. http.Error(w, "invalid share name", http.StatusBadRequest)
  2550. return
  2551. }
  2552. http.Error(w, err.Error(), http.StatusInternalServerError)
  2553. return
  2554. }
  2555. w.WriteHeader(http.StatusNoContent)
  2556. case httpm.GET:
  2557. shares := h.b.DriveGetShares()
  2558. err := json.NewEncoder(w).Encode(shares)
  2559. if err != nil {
  2560. http.Error(w, err.Error(), http.StatusInternalServerError)
  2561. return
  2562. }
  2563. default:
  2564. http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
  2565. }
  2566. }
  2567. // serveSuggestExitNode serves a POST endpoint for returning a suggested exit node.
  2568. func (h *Handler) serveSuggestExitNode(w http.ResponseWriter, r *http.Request) {
  2569. if r.Method != httpm.GET {
  2570. http.Error(w, "only GET allowed", http.StatusMethodNotAllowed)
  2571. return
  2572. }
  2573. res, err := h.b.SuggestExitNode()
  2574. if err != nil {
  2575. WriteErrorJSON(w, err)
  2576. return
  2577. }
  2578. w.Header().Set("Content-Type", "application/json")
  2579. json.NewEncoder(w).Encode(res)
  2580. }