tsweb.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Package tsweb contains code used in various Tailscale webservers.
  4. package tsweb
  5. import (
  6. "bufio"
  7. "bytes"
  8. "context"
  9. "errors"
  10. "expvar"
  11. "fmt"
  12. "net"
  13. "net/http"
  14. _ "net/http/pprof"
  15. "net/netip"
  16. "os"
  17. "path/filepath"
  18. "strconv"
  19. "strings"
  20. "sync"
  21. "time"
  22. "go4.org/mem"
  23. "tailscale.com/envknob"
  24. "tailscale.com/net/tsaddr"
  25. "tailscale.com/tsweb/varz"
  26. "tailscale.com/types/logger"
  27. "tailscale.com/util/cmpx"
  28. "tailscale.com/util/vizerror"
  29. )
  30. // DevMode controls whether extra output in shown, for when the binary is being run in dev mode.
  31. var DevMode bool
  32. func DefaultCertDir(leafDir string) string {
  33. cacheDir, err := os.UserCacheDir()
  34. if err == nil {
  35. return filepath.Join(cacheDir, "tailscale", leafDir)
  36. }
  37. return ""
  38. }
  39. // IsProd443 reports whether addr is a Go listen address for port 443.
  40. func IsProd443(addr string) bool {
  41. _, port, _ := net.SplitHostPort(addr)
  42. return port == "443" || port == "https"
  43. }
  44. // AllowDebugAccess reports whether r should be permitted to access
  45. // various debug endpoints.
  46. func AllowDebugAccess(r *http.Request) bool {
  47. if allowDebugAccessWithKey(r) {
  48. return true
  49. }
  50. if r.Header.Get("X-Forwarded-For") != "" {
  51. // TODO if/when needed. For now, conservative:
  52. return false
  53. }
  54. ipStr, _, err := net.SplitHostPort(r.RemoteAddr)
  55. if err != nil {
  56. return false
  57. }
  58. ip, err := netip.ParseAddr(ipStr)
  59. if err != nil {
  60. return false
  61. }
  62. if tsaddr.IsTailscaleIP(ip) || ip.IsLoopback() || ipStr == envknob.String("TS_ALLOW_DEBUG_IP") {
  63. return true
  64. }
  65. return false
  66. }
  67. func allowDebugAccessWithKey(r *http.Request) bool {
  68. if r.Method != "GET" {
  69. return false
  70. }
  71. urlKey := r.FormValue("debugkey")
  72. keyPath := envknob.String("TS_DEBUG_KEY_PATH")
  73. if urlKey != "" && keyPath != "" {
  74. slurp, err := os.ReadFile(keyPath)
  75. if err == nil && string(bytes.TrimSpace(slurp)) == urlKey {
  76. return true
  77. }
  78. }
  79. return false
  80. }
  81. // AcceptsEncoding reports whether r accepts the named encoding
  82. // ("gzip", "br", etc).
  83. func AcceptsEncoding(r *http.Request, enc string) bool {
  84. h := r.Header.Get("Accept-Encoding")
  85. if h == "" {
  86. return false
  87. }
  88. if !strings.Contains(h, enc) && !mem.ContainsFold(mem.S(h), mem.S(enc)) {
  89. return false
  90. }
  91. remain := h
  92. for len(remain) > 0 {
  93. var part string
  94. part, remain, _ = strings.Cut(remain, ",")
  95. part = strings.TrimSpace(part)
  96. part, _, _ = strings.Cut(part, ";")
  97. if part == enc {
  98. return true
  99. }
  100. }
  101. return false
  102. }
  103. // Protected wraps a provided debug handler, h, returning a Handler
  104. // that enforces AllowDebugAccess and returns forbidden replies for
  105. // unauthorized requests.
  106. func Protected(h http.Handler) http.Handler {
  107. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  108. if !AllowDebugAccess(r) {
  109. msg := "debug access denied"
  110. if DevMode {
  111. ipStr, _, _ := net.SplitHostPort(r.RemoteAddr)
  112. msg += fmt.Sprintf("; to permit access, set TS_ALLOW_DEBUG_IP=%v", ipStr)
  113. }
  114. http.Error(w, msg, http.StatusForbidden)
  115. return
  116. }
  117. h.ServeHTTP(w, r)
  118. })
  119. }
  120. // Port80Handler is the handler to be given to
  121. // autocert.Manager.HTTPHandler. The inner handler is the mux
  122. // returned by NewMux containing registered /debug handlers.
  123. type Port80Handler struct {
  124. Main http.Handler
  125. // FQDN is used to redirect incoming requests to https://<FQDN>.
  126. // If it is not set, the hostname is calculated from the incoming
  127. // request.
  128. FQDN string
  129. }
  130. func (h Port80Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  131. path := r.RequestURI
  132. if path == "/debug" || strings.HasPrefix(path, "/debug") {
  133. h.Main.ServeHTTP(w, r)
  134. return
  135. }
  136. if r.Method != "GET" && r.Method != "HEAD" {
  137. http.Error(w, "Use HTTPS", http.StatusBadRequest)
  138. return
  139. }
  140. if path == "/" && AllowDebugAccess(r) {
  141. // Redirect authorized user to the debug handler.
  142. path = "/debug/"
  143. }
  144. host := cmpx.Or(h.FQDN, r.Host)
  145. target := "https://" + host + path
  146. http.Redirect(w, r, target, http.StatusFound)
  147. }
  148. // ReturnHandler is like net/http.Handler, but the handler can return an
  149. // error instead of writing to its ResponseWriter.
  150. type ReturnHandler interface {
  151. // ServeHTTPReturn is like http.Handler.ServeHTTP, except that
  152. // it can choose to return an error instead of writing to its
  153. // http.ResponseWriter.
  154. //
  155. // If ServeHTTPReturn returns an error, it caller should handle
  156. // an error by serving an HTTP 500 response to the user. The
  157. // error details should not be sent to the client, as they may
  158. // contain sensitive information. If the error is an
  159. // HTTPError, though, callers should use the HTTP response
  160. // code and message as the response to the client.
  161. ServeHTTPReturn(http.ResponseWriter, *http.Request) error
  162. }
  163. type HandlerOptions struct {
  164. QuietLoggingIfSuccessful bool // if set, do not log successfully handled HTTP requests (200 and 304 status codes)
  165. Logf logger.Logf
  166. Now func() time.Time // if nil, defaults to time.Now
  167. // If non-nil, StatusCodeCounters maintains counters
  168. // of status codes for handled responses.
  169. // The keys are "1xx", "2xx", "3xx", "4xx", and "5xx".
  170. StatusCodeCounters *expvar.Map
  171. // If non-nil, StatusCodeCountersFull maintains counters of status
  172. // codes for handled responses.
  173. // The keys are HTTP numeric response codes e.g. 200, 404, ...
  174. StatusCodeCountersFull *expvar.Map
  175. // OnError is called if the handler returned a HTTPError. This
  176. // is intended to be used to present pretty error pages if
  177. // the user agent is determined to be a browser.
  178. OnError ErrorHandlerFunc
  179. }
  180. // ErrorHandlerFunc is called to present a error response.
  181. type ErrorHandlerFunc func(http.ResponseWriter, *http.Request, HTTPError)
  182. // ReturnHandlerFunc is an adapter to allow the use of ordinary
  183. // functions as ReturnHandlers. If f is a function with the
  184. // appropriate signature, ReturnHandlerFunc(f) is a ReturnHandler that
  185. // calls f.
  186. type ReturnHandlerFunc func(http.ResponseWriter, *http.Request) error
  187. // A Middleware is a function that wraps an http.Handler to extend or modify
  188. // its behaviour.
  189. //
  190. // The implementation of the wrapper is responsible for delegating its input
  191. // request to the underlying handler, if appropriate.
  192. type Middleware func(h http.Handler) http.Handler
  193. // ServeHTTPReturn calls f(w, r).
  194. func (f ReturnHandlerFunc) ServeHTTPReturn(w http.ResponseWriter, r *http.Request) error {
  195. return f(w, r)
  196. }
  197. // StdHandler converts a ReturnHandler into a standard http.Handler.
  198. // Handled requests are logged using opts.Logf, as are any errors.
  199. // Errors are handled as specified by the Handler interface.
  200. func StdHandler(h ReturnHandler, opts HandlerOptions) http.Handler {
  201. if opts.Now == nil {
  202. opts.Now = time.Now
  203. }
  204. if opts.Logf == nil {
  205. opts.Logf = logger.Discard
  206. }
  207. return retHandler{h, opts}
  208. }
  209. // retHandler is an http.Handler that wraps a Handler and handles errors.
  210. type retHandler struct {
  211. rh ReturnHandler
  212. opts HandlerOptions
  213. }
  214. // ServeHTTP implements the http.Handler interface.
  215. func (h retHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  216. msg := AccessLogRecord{
  217. When: h.opts.Now(),
  218. RemoteAddr: r.RemoteAddr,
  219. Proto: r.Proto,
  220. TLS: r.TLS != nil,
  221. Host: r.Host,
  222. Method: r.Method,
  223. RequestURI: r.URL.RequestURI(),
  224. UserAgent: r.UserAgent(),
  225. Referer: r.Referer(),
  226. RequestID: RequestIDFromContext(r.Context()),
  227. }
  228. lw := &loggingResponseWriter{ResponseWriter: w, logf: h.opts.Logf}
  229. err := h.rh.ServeHTTPReturn(lw, r)
  230. var hErr HTTPError
  231. var hErrOK bool
  232. if errors.As(err, &hErr) {
  233. hErrOK = true
  234. } else if vizErr, ok := vizerror.As(err); ok {
  235. hErrOK = true
  236. hErr = HTTPError{Msg: vizErr.Error()}
  237. }
  238. if lw.code == 0 && err == nil && !lw.hijacked {
  239. // If the handler didn't write and didn't send a header, that still means 200.
  240. // (See https://play.golang.org/p/4P7nx_Tap7p)
  241. lw.code = 200
  242. }
  243. msg.Seconds = h.opts.Now().Sub(msg.When).Seconds()
  244. msg.Code = lw.code
  245. msg.Bytes = lw.bytes
  246. switch {
  247. case lw.hijacked:
  248. // Connection no longer belongs to us, just log that we
  249. // switched protocols away from HTTP.
  250. if msg.Code == 0 {
  251. msg.Code = http.StatusSwitchingProtocols
  252. }
  253. case err != nil && r.Context().Err() == context.Canceled:
  254. msg.Code = 499 // nginx convention: Client Closed Request
  255. msg.Err = context.Canceled.Error()
  256. case hErrOK:
  257. // Handler asked us to send an error. Do so, if we haven't
  258. // already sent a response.
  259. msg.Err = hErr.Msg
  260. if hErr.Err != nil {
  261. if msg.Err == "" {
  262. msg.Err = hErr.Err.Error()
  263. } else {
  264. msg.Err = msg.Err + ": " + hErr.Err.Error()
  265. }
  266. }
  267. if lw.code != 0 {
  268. h.opts.Logf("[unexpected] handler returned HTTPError %v, but already sent a response with code %d", hErr, lw.code)
  269. break
  270. }
  271. msg.Code = hErr.Code
  272. if msg.Code == 0 {
  273. h.opts.Logf("[unexpected] HTTPError %v did not contain an HTTP status code, sending internal server error", hErr)
  274. msg.Code = http.StatusInternalServerError
  275. }
  276. if h.opts.OnError != nil {
  277. h.opts.OnError(lw, r, hErr)
  278. } else {
  279. // Default headers set by http.Error.
  280. lw.Header().Set("Content-Type", "text/plain; charset=utf-8")
  281. lw.Header().Set("X-Content-Type-Options", "nosniff")
  282. for k, vs := range hErr.Header {
  283. lw.Header()[k] = vs
  284. }
  285. lw.WriteHeader(msg.Code)
  286. fmt.Fprintln(lw, hErr.Msg)
  287. if msg.RequestID != "" {
  288. fmt.Fprintln(lw, msg.RequestID)
  289. }
  290. }
  291. case err != nil:
  292. const internalServerError = "internal server error"
  293. errorMessage := internalServerError
  294. if msg.RequestID != "" {
  295. errorMessage += "\n" + string(msg.RequestID)
  296. }
  297. // Handler returned a generic error. Serve an internal server
  298. // error, if necessary.
  299. msg.Err = err.Error()
  300. if lw.code == 0 {
  301. msg.Code = http.StatusInternalServerError
  302. http.Error(lw, errorMessage, msg.Code)
  303. }
  304. }
  305. if !h.opts.QuietLoggingIfSuccessful || (msg.Code != http.StatusOK && msg.Code != http.StatusNotModified) {
  306. h.opts.Logf("%s", msg)
  307. }
  308. if h.opts.StatusCodeCounters != nil {
  309. h.opts.StatusCodeCounters.Add(responseCodeString(msg.Code/100), 1)
  310. }
  311. if h.opts.StatusCodeCountersFull != nil {
  312. h.opts.StatusCodeCountersFull.Add(responseCodeString(msg.Code), 1)
  313. }
  314. }
  315. func responseCodeString(code int) string {
  316. if v, ok := responseCodeCache.Load(code); ok {
  317. return v.(string)
  318. }
  319. var ret string
  320. if code < 10 {
  321. ret = fmt.Sprintf("%dxx", code)
  322. } else {
  323. ret = strconv.Itoa(code)
  324. }
  325. responseCodeCache.Store(code, ret)
  326. return ret
  327. }
  328. // responseCodeCache memoizes the string form of HTTP response codes,
  329. // so that the hot request-handling codepath doesn't have to allocate
  330. // in strconv/fmt for every request.
  331. //
  332. // Keys are either full HTTP response code ints (200, 404) or "family"
  333. // ints representing entire families (e.g. 2 for 2xx codes). Values
  334. // are the string form of that code/family.
  335. var responseCodeCache sync.Map
  336. // loggingResponseWriter wraps a ResponseWriter and record the HTTP
  337. // response code that gets sent, if any.
  338. type loggingResponseWriter struct {
  339. http.ResponseWriter
  340. code int
  341. bytes int
  342. hijacked bool
  343. logf logger.Logf
  344. }
  345. // WriteHeader implements http.Handler.
  346. func (l *loggingResponseWriter) WriteHeader(statusCode int) {
  347. if l.code != 0 {
  348. l.logf("[unexpected] HTTP handler set statusCode twice (%d and %d)", l.code, statusCode)
  349. return
  350. }
  351. l.code = statusCode
  352. l.ResponseWriter.WriteHeader(statusCode)
  353. }
  354. // Write implements http.Handler.
  355. func (l *loggingResponseWriter) Write(bs []byte) (int, error) {
  356. if l.code == 0 {
  357. l.code = 200
  358. }
  359. n, err := l.ResponseWriter.Write(bs)
  360. l.bytes += n
  361. return n, err
  362. }
  363. // Hijack implements http.Hijacker. Note that hijacking can still fail
  364. // because the wrapped ResponseWriter is not required to implement
  365. // Hijacker, as this breaks HTTP/2.
  366. func (l *loggingResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
  367. h, ok := l.ResponseWriter.(http.Hijacker)
  368. if !ok {
  369. return nil, nil, errors.New("ResponseWriter is not a Hijacker")
  370. }
  371. conn, buf, err := h.Hijack()
  372. if err == nil {
  373. l.hijacked = true
  374. }
  375. return conn, buf, err
  376. }
  377. func (l loggingResponseWriter) Flush() {
  378. f, _ := l.ResponseWriter.(http.Flusher)
  379. if f == nil {
  380. l.logf("[unexpected] tried to Flush a ResponseWriter that can't flush")
  381. return
  382. }
  383. f.Flush()
  384. }
  385. // HTTPError is an error with embedded HTTP response information.
  386. //
  387. // It is the error type to be (optionally) used by Handler.ServeHTTPReturn.
  388. type HTTPError struct {
  389. Code int // HTTP response code to send to client; 0 means 500
  390. Msg string // Response body to send to client
  391. Err error // Detailed error to log on the server
  392. Header http.Header // Optional set of HTTP headers to set in the response
  393. }
  394. // Error implements the error interface.
  395. func (e HTTPError) Error() string { return fmt.Sprintf("httperror{%d, %q, %v}", e.Code, e.Msg, e.Err) }
  396. func (e HTTPError) Unwrap() error { return e.Err }
  397. // Error returns an HTTPError containing the given information.
  398. func Error(code int, msg string, err error) HTTPError {
  399. return HTTPError{Code: code, Msg: msg, Err: err}
  400. }
  401. // VarzHandler writes expvar values as Prometheus metrics.
  402. // TODO: migrate all users to varz.Handler or promvarz.Handler and remove this.
  403. func VarzHandler(w http.ResponseWriter, r *http.Request) {
  404. varz.Handler(w, r)
  405. }
  406. // AddBrowserHeaders sets various HTTP security headers for browser-facing endpoints.
  407. //
  408. // The specific headers:
  409. // - require HTTPS access (HSTS)
  410. // - disallow iframe embedding
  411. // - mitigate MIME confusion attacks
  412. //
  413. // These headers are based on
  414. // https://infosec.mozilla.org/guidelines/web_security
  415. func AddBrowserHeaders(w http.ResponseWriter) {
  416. w.Header().Set("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
  417. w.Header().Set("Content-Security-Policy", "default-src 'self'; frame-ancestors 'none'; form-action 'self'; base-uri 'self'; block-all-mixed-content; plugin-types 'none'")
  418. w.Header().Set("X-Frame-Options", "DENY")
  419. w.Header().Set("X-Content-Type-Options", "nosniff")
  420. }
  421. // BrowserHeaderHandler wraps the provided http.Handler with a call to
  422. // AddBrowserHeaders.
  423. func BrowserHeaderHandler(h http.Handler) http.Handler {
  424. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  425. AddBrowserHeaders(w)
  426. h.ServeHTTP(w, r)
  427. })
  428. }
  429. // BrowserHeaderHandlerFunc wraps the provided http.HandlerFunc with a call to
  430. // AddBrowserHeaders.
  431. func BrowserHeaderHandlerFunc(h http.HandlerFunc) http.HandlerFunc {
  432. return func(w http.ResponseWriter, r *http.Request) {
  433. AddBrowserHeaders(w)
  434. h.ServeHTTP(w, r)
  435. }
  436. }