localapi.go 86 KB

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