auto.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package controlclient
  4. import (
  5. "context"
  6. "errors"
  7. "fmt"
  8. "net/http"
  9. "sync"
  10. "sync/atomic"
  11. "time"
  12. "tailscale.com/health"
  13. "tailscale.com/logtail/backoff"
  14. "tailscale.com/net/sockstats"
  15. "tailscale.com/tailcfg"
  16. "tailscale.com/tstime"
  17. "tailscale.com/types/empty"
  18. "tailscale.com/types/key"
  19. "tailscale.com/types/logger"
  20. "tailscale.com/types/netmap"
  21. "tailscale.com/types/persist"
  22. "tailscale.com/types/ptr"
  23. "tailscale.com/types/structs"
  24. )
  25. type LoginGoal struct {
  26. _ structs.Incomparable
  27. wantLoggedIn bool // true if we *want* to be logged in
  28. token *tailcfg.Oauth2Token // oauth token to use when logging in
  29. flags LoginFlags // flags to use when logging in
  30. url string // auth url that needs to be visited
  31. loggedOutResult chan<- error
  32. }
  33. func (g *LoginGoal) sendLogoutError(err error) {
  34. if g.loggedOutResult == nil {
  35. return
  36. }
  37. select {
  38. case g.loggedOutResult <- err:
  39. default:
  40. }
  41. }
  42. var _ Client = (*Auto)(nil)
  43. // waitUnpause waits until the client is unpaused then returns. It only
  44. // returns an error if the client is closed.
  45. func (c *Auto) waitUnpause(routineLogName string) error {
  46. c.mu.Lock()
  47. if !c.paused {
  48. c.mu.Unlock()
  49. return nil
  50. }
  51. unpaused := c.unpausedChanLocked()
  52. c.mu.Unlock()
  53. c.logf("%s: awaiting unpause", routineLogName)
  54. select {
  55. case <-unpaused:
  56. c.logf("%s: unpaused", routineLogName)
  57. return nil
  58. case <-c.quit:
  59. return errors.New("quit")
  60. }
  61. }
  62. // updateRoutine is responsible for informing the server of worthy changes to
  63. // our local state. It runs in its own goroutine.
  64. func (c *Auto) updateRoutine() {
  65. defer close(c.updateDone)
  66. bo := backoff.NewBackoff("updateRoutine", c.logf, 30*time.Second)
  67. // lastUpdateGenInformed is the value of lastUpdateAt that we've successfully
  68. // informed the server of.
  69. var lastUpdateGenInformed updateGen
  70. for {
  71. if err := c.waitUnpause("updateRoutine"); err != nil {
  72. c.logf("updateRoutine: exiting")
  73. return
  74. }
  75. c.mu.Lock()
  76. gen := c.lastUpdateGen
  77. ctx := c.mapCtx
  78. needUpdate := gen > 0 && gen != lastUpdateGenInformed && c.loggedIn
  79. c.mu.Unlock()
  80. if needUpdate {
  81. select {
  82. case <-c.quit:
  83. c.logf("updateRoutine: exiting")
  84. return
  85. default:
  86. }
  87. } else {
  88. // Nothing to do, wait for a signal.
  89. select {
  90. case <-c.quit:
  91. c.logf("updateRoutine: exiting")
  92. return
  93. case <-c.updateCh:
  94. continue
  95. }
  96. }
  97. t0 := c.clock.Now()
  98. err := c.direct.SendUpdate(ctx)
  99. d := time.Since(t0).Round(time.Millisecond)
  100. if err != nil {
  101. if ctx.Err() == nil {
  102. c.direct.logf("lite map update error after %v: %v", d, err)
  103. }
  104. bo.BackOff(ctx, err)
  105. continue
  106. }
  107. bo.BackOff(ctx, nil)
  108. c.direct.logf("[v1] successful lite map update in %v", d)
  109. lastUpdateGenInformed = gen
  110. }
  111. }
  112. // atomicGen is an atomic int64 generator. It is used to generate monotonically
  113. // increasing numbers for updateGen.
  114. var atomicGen atomic.Int64
  115. func nextUpdateGen() updateGen {
  116. return updateGen(atomicGen.Add(1))
  117. }
  118. // updateGen is a monotonically increasing number that represents a particular
  119. // update to the local state.
  120. type updateGen int64
  121. // Auto connects to a tailcontrol server for a node.
  122. // It's a concrete implementation of the Client interface.
  123. type Auto struct {
  124. direct *Direct // our interface to the server APIs
  125. clock tstime.Clock
  126. logf logger.Logf
  127. expiry *time.Time
  128. closed bool
  129. updateCh chan struct{} // readable when we should inform the server of a change
  130. newMapCh chan struct{} // readable when we must restart a map request
  131. statusFunc func(Status) // called to update Client status; always non-nil
  132. unregisterHealthWatch func()
  133. mu sync.Mutex // mutex guards the following fields
  134. // lastUpdateGen is the gen of last update we had an update worth sending to
  135. // the server.
  136. lastUpdateGen updateGen
  137. paused bool // whether we should stop making HTTP requests
  138. unpauseWaiters []chan struct{}
  139. loggedIn bool // true if currently logged in
  140. loginGoal *LoginGoal // non-nil if some login activity is desired
  141. synced bool // true if our netmap is up-to-date
  142. inSendStatus int // number of sendStatus calls currently in progress
  143. state State
  144. authCtx context.Context // context used for auth requests
  145. mapCtx context.Context // context used for netmap and update requests
  146. authCancel func() // cancel authCtx
  147. mapCancel func() // cancel mapCtx
  148. quit chan struct{} // when closed, goroutines should all exit
  149. authDone chan struct{} // when closed, authRoutine is done
  150. mapDone chan struct{} // when closed, mapRoutine is done
  151. updateDone chan struct{} // when closed, updateRoutine is done
  152. }
  153. // New creates and starts a new Auto.
  154. func New(opts Options) (*Auto, error) {
  155. c, err := NewNoStart(opts)
  156. if c != nil {
  157. c.Start()
  158. }
  159. return c, err
  160. }
  161. // NewNoStart creates a new Auto, but without calling Start on it.
  162. func NewNoStart(opts Options) (_ *Auto, err error) {
  163. direct, err := NewDirect(opts)
  164. if err != nil {
  165. return nil, err
  166. }
  167. defer func() {
  168. if err != nil {
  169. direct.Close()
  170. }
  171. }()
  172. if opts.Status == nil {
  173. return nil, errors.New("missing required Options.Status")
  174. }
  175. if opts.Logf == nil {
  176. opts.Logf = func(fmt string, args ...any) {}
  177. }
  178. if opts.Clock == nil {
  179. opts.Clock = tstime.StdClock{}
  180. }
  181. c := &Auto{
  182. direct: direct,
  183. clock: opts.Clock,
  184. logf: opts.Logf,
  185. updateCh: make(chan struct{}, 1),
  186. newMapCh: make(chan struct{}, 1),
  187. quit: make(chan struct{}),
  188. authDone: make(chan struct{}),
  189. mapDone: make(chan struct{}),
  190. updateDone: make(chan struct{}),
  191. statusFunc: opts.Status,
  192. }
  193. c.authCtx, c.authCancel = context.WithCancel(context.Background())
  194. c.authCtx = sockstats.WithSockStats(c.authCtx, sockstats.LabelControlClientAuto, opts.Logf)
  195. c.mapCtx, c.mapCancel = context.WithCancel(context.Background())
  196. c.mapCtx = sockstats.WithSockStats(c.mapCtx, sockstats.LabelControlClientAuto, opts.Logf)
  197. c.unregisterHealthWatch = health.RegisterWatcher(direct.ReportHealthChange)
  198. return c, nil
  199. }
  200. // SetPaused controls whether HTTP activity should be paused.
  201. //
  202. // The client can be paused and unpaused repeatedly, unlike Start and Shutdown, which can only be used once.
  203. func (c *Auto) SetPaused(paused bool) {
  204. c.mu.Lock()
  205. defer c.mu.Unlock()
  206. if paused == c.paused {
  207. return
  208. }
  209. c.logf("setPaused(%v)", paused)
  210. c.paused = paused
  211. if paused {
  212. // Only cancel the map routine. (The auth routine isn't expensive
  213. // so it's fine to keep it running.)
  214. c.cancelMapLocked()
  215. } else {
  216. for _, ch := range c.unpauseWaiters {
  217. close(ch)
  218. }
  219. c.unpauseWaiters = nil
  220. }
  221. }
  222. // Start starts the client's goroutines.
  223. //
  224. // It should only be called for clients created by NewNoStart.
  225. func (c *Auto) Start() {
  226. go c.authRoutine()
  227. go c.mapRoutine()
  228. go c.updateRoutine()
  229. }
  230. // updateControl sends a new OmitPeers, non-streaming map request (to just send
  231. // Hostinfo/Netinfo/Endpoints info, while keeping an existing streaming response
  232. // open).
  233. //
  234. // It should be called whenever there's something new to tell the server.
  235. func (c *Auto) updateControl() {
  236. gen := nextUpdateGen()
  237. c.mu.Lock()
  238. if gen < c.lastUpdateGen {
  239. // This update is out of date.
  240. c.mu.Unlock()
  241. return
  242. }
  243. c.lastUpdateGen = gen
  244. c.mu.Unlock()
  245. select {
  246. case c.updateCh <- struct{}{}:
  247. default:
  248. }
  249. }
  250. func (c *Auto) cancelAuth() {
  251. c.mu.Lock()
  252. defer c.mu.Unlock()
  253. if c.authCancel != nil {
  254. c.authCancel()
  255. }
  256. if !c.closed {
  257. c.authCtx, c.authCancel = context.WithCancel(context.Background())
  258. c.authCtx = sockstats.WithSockStats(c.authCtx, sockstats.LabelControlClientAuto, c.logf)
  259. }
  260. }
  261. // cancelMapLocked is like cancelMap, but assumes the caller holds c.mu.
  262. func (c *Auto) cancelMapLocked() {
  263. if c.mapCancel != nil {
  264. c.mapCancel()
  265. }
  266. if !c.closed {
  267. c.mapCtx, c.mapCancel = context.WithCancel(context.Background())
  268. c.mapCtx = sockstats.WithSockStats(c.mapCtx, sockstats.LabelControlClientAuto, c.logf)
  269. }
  270. }
  271. // cancelMap cancels the existing mapPoll and liteUpdates.
  272. func (c *Auto) cancelMap() {
  273. c.mu.Lock()
  274. defer c.mu.Unlock()
  275. c.cancelMapLocked()
  276. }
  277. // restartMap cancels the existing mapPoll and liteUpdates, and then starts a
  278. // new one.
  279. func (c *Auto) restartMap() {
  280. c.mu.Lock()
  281. c.cancelMapLocked()
  282. synced := c.synced
  283. c.mu.Unlock()
  284. c.logf("[v1] restartMap: synced=%v", synced)
  285. select {
  286. case c.newMapCh <- struct{}{}:
  287. c.logf("[v1] restartMap: wrote to channel")
  288. default:
  289. // if channel write failed, then there was already
  290. // an outstanding newMapCh request. One is enough,
  291. // since it'll always use the latest endpoints.
  292. c.logf("[v1] restartMap: channel was full")
  293. }
  294. c.updateControl()
  295. }
  296. func (c *Auto) authRoutine() {
  297. defer close(c.authDone)
  298. bo := backoff.NewBackoff("authRoutine", c.logf, 30*time.Second)
  299. for {
  300. c.mu.Lock()
  301. goal := c.loginGoal
  302. ctx := c.authCtx
  303. if goal != nil {
  304. c.logf("[v1] authRoutine: %s; wantLoggedIn=%v", c.state, goal.wantLoggedIn)
  305. } else {
  306. c.logf("[v1] authRoutine: %s; goal=nil paused=%v", c.state, c.paused)
  307. }
  308. c.mu.Unlock()
  309. select {
  310. case <-c.quit:
  311. c.logf("[v1] authRoutine: quit")
  312. return
  313. default:
  314. }
  315. report := func(err error, msg string) {
  316. c.logf("[v1] %s: %v", msg, err)
  317. // don't send status updates for context errors,
  318. // since context cancelation is always on purpose.
  319. if ctx.Err() == nil {
  320. c.sendStatus("authRoutine-report", err, "", nil)
  321. }
  322. }
  323. if goal == nil {
  324. health.SetAuthRoutineInError(nil)
  325. // Wait for user to Login or Logout.
  326. <-ctx.Done()
  327. c.logf("[v1] authRoutine: context done.")
  328. continue
  329. }
  330. if !goal.wantLoggedIn {
  331. health.SetAuthRoutineInError(nil)
  332. err := c.direct.TryLogout(ctx)
  333. goal.sendLogoutError(err)
  334. if err != nil {
  335. report(err, "TryLogout")
  336. bo.BackOff(ctx, err)
  337. continue
  338. }
  339. // success
  340. c.mu.Lock()
  341. c.loggedIn = false
  342. c.loginGoal = nil
  343. c.state = StateNotAuthenticated
  344. c.synced = false
  345. c.mu.Unlock()
  346. c.sendStatus("authRoutine-wantout", nil, "", nil)
  347. bo.BackOff(ctx, nil)
  348. } else { // ie. goal.wantLoggedIn
  349. c.mu.Lock()
  350. if goal.url != "" {
  351. c.state = StateURLVisitRequired
  352. } else {
  353. c.state = StateAuthenticating
  354. }
  355. c.mu.Unlock()
  356. var url string
  357. var err error
  358. var f string
  359. if goal.url != "" {
  360. url, err = c.direct.WaitLoginURL(ctx, goal.url)
  361. f = "WaitLoginURL"
  362. } else {
  363. url, err = c.direct.TryLogin(ctx, goal.token, goal.flags)
  364. f = "TryLogin"
  365. }
  366. if err != nil {
  367. health.SetAuthRoutineInError(err)
  368. report(err, f)
  369. bo.BackOff(ctx, err)
  370. continue
  371. }
  372. if url != "" {
  373. // goal.url ought to be empty here.
  374. // However, not all control servers get this right,
  375. // and logging about it here just generates noise.
  376. c.mu.Lock()
  377. c.loginGoal = &LoginGoal{
  378. wantLoggedIn: true,
  379. flags: LoginDefault,
  380. url: url,
  381. }
  382. c.state = StateURLVisitRequired
  383. c.synced = false
  384. c.mu.Unlock()
  385. c.sendStatus("authRoutine-url", err, url, nil)
  386. if goal.url == url {
  387. // The server sent us the same URL we already tried,
  388. // backoff to avoid a busy loop.
  389. bo.BackOff(ctx, errors.New("login URL not changing"))
  390. } else {
  391. bo.BackOff(ctx, nil)
  392. }
  393. continue
  394. }
  395. // success
  396. health.SetAuthRoutineInError(nil)
  397. c.mu.Lock()
  398. c.loggedIn = true
  399. c.loginGoal = nil
  400. c.state = StateAuthenticated
  401. c.mu.Unlock()
  402. c.sendStatus("authRoutine-success", nil, "", nil)
  403. c.restartMap()
  404. bo.BackOff(ctx, nil)
  405. }
  406. }
  407. }
  408. // Expiry returns the credential expiration time, or the zero time if
  409. // the expiration time isn't known. Used in tests only.
  410. func (c *Auto) Expiry() *time.Time {
  411. c.mu.Lock()
  412. defer c.mu.Unlock()
  413. return c.expiry
  414. }
  415. // Direct returns the underlying direct client object. Used in tests
  416. // only.
  417. func (c *Auto) Direct() *Direct {
  418. return c.direct
  419. }
  420. // unpausedChanLocked returns a new channel that is closed when the
  421. // current Auto pause is unpaused.
  422. //
  423. // c.mu must be held
  424. func (c *Auto) unpausedChanLocked() <-chan struct{} {
  425. unpaused := make(chan struct{})
  426. c.unpauseWaiters = append(c.unpauseWaiters, unpaused)
  427. return unpaused
  428. }
  429. // mapRoutineState is the state of Auto.mapRoutine while it's running.
  430. type mapRoutineState struct {
  431. c *Auto
  432. bo *backoff.Backoff
  433. }
  434. func (mrs mapRoutineState) UpdateFullNetmap(nm *netmap.NetworkMap) {
  435. c := mrs.c
  436. health.SetInPollNetMap(true)
  437. c.mu.Lock()
  438. ctx := c.mapCtx
  439. c.synced = true
  440. if c.loggedIn {
  441. c.state = StateSynchronized
  442. }
  443. c.expiry = ptr.To(nm.Expiry)
  444. stillAuthed := c.loggedIn
  445. c.logf("[v1] mapRoutine: netmap received: %s", c.state)
  446. c.mu.Unlock()
  447. if stillAuthed {
  448. c.sendStatus("mapRoutine-got-netmap", nil, "", nm)
  449. }
  450. // Reset the backoff timer if we got a netmap.
  451. mrs.bo.BackOff(ctx, nil)
  452. }
  453. // mapRoutine is responsible for keeping a read-only streaming connection to the
  454. // control server, and keeping the netmap up to date.
  455. func (c *Auto) mapRoutine() {
  456. defer close(c.mapDone)
  457. mrs := &mapRoutineState{
  458. c: c,
  459. bo: backoff.NewBackoff("mapRoutine", c.logf, 30*time.Second),
  460. }
  461. for {
  462. if err := c.waitUnpause("mapRoutine"); err != nil {
  463. c.logf("mapRoutine: exiting")
  464. return
  465. }
  466. c.mu.Lock()
  467. c.logf("[v1] mapRoutine: %s", c.state)
  468. loggedIn := c.loggedIn
  469. ctx := c.mapCtx
  470. c.mu.Unlock()
  471. select {
  472. case <-c.quit:
  473. c.logf("mapRoutine: quit")
  474. return
  475. default:
  476. }
  477. report := func(err error, msg string) {
  478. c.logf("[v1] %s: %v", msg, err)
  479. err = fmt.Errorf("%s: %w", msg, err)
  480. // don't send status updates for context errors,
  481. // since context cancelation is always on purpose.
  482. if ctx.Err() == nil {
  483. c.sendStatus("mapRoutine1", err, "", nil)
  484. }
  485. }
  486. if !loggedIn {
  487. // Wait for something interesting to happen
  488. c.mu.Lock()
  489. c.synced = false
  490. // c.state is set by authRoutine()
  491. c.mu.Unlock()
  492. select {
  493. case <-ctx.Done():
  494. c.logf("[v1] mapRoutine: context done.")
  495. case <-c.newMapCh:
  496. c.logf("[v1] mapRoutine: new map needed while idle.")
  497. }
  498. } else {
  499. health.SetInPollNetMap(false)
  500. err := c.direct.PollNetMap(ctx, mrs)
  501. health.SetInPollNetMap(false)
  502. c.mu.Lock()
  503. c.synced = false
  504. if c.state == StateSynchronized {
  505. c.state = StateAuthenticated
  506. }
  507. paused := c.paused
  508. c.mu.Unlock()
  509. if paused {
  510. mrs.bo.BackOff(ctx, nil)
  511. c.logf("mapRoutine: paused")
  512. continue
  513. }
  514. report(err, "PollNetMap")
  515. mrs.bo.BackOff(ctx, err)
  516. continue
  517. }
  518. }
  519. }
  520. func (c *Auto) AuthCantContinue() bool {
  521. if c == nil {
  522. return true
  523. }
  524. c.mu.Lock()
  525. defer c.mu.Unlock()
  526. return !c.loggedIn && (c.loginGoal == nil || c.loginGoal.url != "")
  527. }
  528. func (c *Auto) SetHostinfo(hi *tailcfg.Hostinfo) {
  529. if hi == nil {
  530. panic("nil Hostinfo")
  531. }
  532. if !c.direct.SetHostinfo(hi) {
  533. // No changes. Don't log.
  534. return
  535. }
  536. // Send new Hostinfo to server
  537. c.updateControl()
  538. }
  539. func (c *Auto) SetNetInfo(ni *tailcfg.NetInfo) {
  540. if ni == nil {
  541. panic("nil NetInfo")
  542. }
  543. if !c.direct.SetNetInfo(ni) {
  544. return
  545. }
  546. // Send new NetInfo to server
  547. c.updateControl()
  548. }
  549. // SetTKAHead updates the TKA head hash that map-request infrastructure sends.
  550. func (c *Auto) SetTKAHead(headHash string) {
  551. if !c.direct.SetTKAHead(headHash) {
  552. return
  553. }
  554. // Send new TKAHead to server
  555. c.updateControl()
  556. }
  557. func (c *Auto) sendStatus(who string, err error, url string, nm *netmap.NetworkMap) {
  558. c.mu.Lock()
  559. if c.closed {
  560. c.mu.Unlock()
  561. return
  562. }
  563. state := c.state
  564. loggedIn := c.loggedIn
  565. synced := c.synced
  566. c.inSendStatus++
  567. c.mu.Unlock()
  568. c.logf("[v1] sendStatus: %s: %v", who, state)
  569. var p *persist.PersistView
  570. var loginFin, logoutFin *empty.Message
  571. if state == StateAuthenticated {
  572. loginFin = new(empty.Message)
  573. }
  574. if state == StateNotAuthenticated {
  575. logoutFin = new(empty.Message)
  576. }
  577. if nm != nil && loggedIn && synced {
  578. p = ptr.To(c.direct.GetPersist())
  579. } else {
  580. // don't send netmap status, as it's misleading when we're
  581. // not logged in.
  582. nm = nil
  583. }
  584. new := Status{
  585. LoginFinished: loginFin,
  586. LogoutFinished: logoutFin,
  587. URL: url,
  588. Persist: p,
  589. NetMap: nm,
  590. State: state,
  591. Err: err,
  592. }
  593. c.statusFunc(new)
  594. c.mu.Lock()
  595. c.inSendStatus--
  596. c.mu.Unlock()
  597. }
  598. func (c *Auto) Login(t *tailcfg.Oauth2Token, flags LoginFlags) {
  599. c.logf("client.Login(%v, %v)", t != nil, flags)
  600. c.mu.Lock()
  601. c.loginGoal = &LoginGoal{
  602. wantLoggedIn: true,
  603. token: t,
  604. flags: flags,
  605. }
  606. c.mu.Unlock()
  607. c.cancelAuth()
  608. }
  609. func (c *Auto) StartLogout() {
  610. c.logf("client.StartLogout()")
  611. c.mu.Lock()
  612. c.loginGoal = &LoginGoal{
  613. wantLoggedIn: false,
  614. }
  615. c.mu.Unlock()
  616. c.cancelAuth()
  617. }
  618. func (c *Auto) Logout(ctx context.Context) error {
  619. c.logf("client.Logout()")
  620. errc := make(chan error, 1)
  621. c.mu.Lock()
  622. c.loginGoal = &LoginGoal{
  623. wantLoggedIn: false,
  624. loggedOutResult: errc,
  625. }
  626. c.mu.Unlock()
  627. c.cancelAuth()
  628. timer, timerChannel := c.clock.NewTimer(10 * time.Second)
  629. defer timer.Stop()
  630. select {
  631. case err := <-errc:
  632. return err
  633. case <-ctx.Done():
  634. return ctx.Err()
  635. case <-timerChannel:
  636. return context.DeadlineExceeded
  637. }
  638. }
  639. func (c *Auto) SetExpirySooner(ctx context.Context, expiry time.Time) error {
  640. return c.direct.SetExpirySooner(ctx, expiry)
  641. }
  642. // UpdateEndpoints sets the client's discovered endpoints and sends
  643. // them to the control server if they've changed.
  644. //
  645. // It does not retain the provided slice.
  646. func (c *Auto) UpdateEndpoints(endpoints []tailcfg.Endpoint) {
  647. changed := c.direct.SetEndpoints(endpoints)
  648. if changed {
  649. c.updateControl()
  650. }
  651. }
  652. func (c *Auto) Shutdown() {
  653. c.logf("client.Shutdown()")
  654. c.mu.Lock()
  655. inSendStatus := c.inSendStatus
  656. closed := c.closed
  657. direct := c.direct
  658. if !closed {
  659. c.closed = true
  660. }
  661. c.mu.Unlock()
  662. c.logf("client.Shutdown: inSendStatus=%v", inSendStatus)
  663. if !closed {
  664. c.unregisterHealthWatch()
  665. close(c.quit)
  666. c.cancelAuth()
  667. <-c.authDone
  668. c.cancelMap()
  669. <-c.mapDone
  670. <-c.updateDone
  671. if direct != nil {
  672. direct.Close()
  673. }
  674. c.logf("Client.Shutdown done.")
  675. }
  676. }
  677. // NodePublicKey returns the node public key currently in use. This is
  678. // used exclusively in tests.
  679. func (c *Auto) TestOnlyNodePublicKey() key.NodePublic {
  680. priv := c.direct.GetPersist()
  681. return priv.PrivateNodeKey().Public()
  682. }
  683. func (c *Auto) TestOnlySetAuthKey(authkey string) {
  684. c.direct.mu.Lock()
  685. defer c.direct.mu.Unlock()
  686. c.direct.authKey = authkey
  687. }
  688. func (c *Auto) TestOnlyTimeNow() time.Time {
  689. return c.clock.Now()
  690. }
  691. // SetDNS sends the SetDNSRequest request to the control plane server,
  692. // requesting a DNS record be created or updated.
  693. func (c *Auto) SetDNS(ctx context.Context, req *tailcfg.SetDNSRequest) error {
  694. return c.direct.SetDNS(ctx, req)
  695. }
  696. func (c *Auto) DoNoiseRequest(req *http.Request) (*http.Response, error) {
  697. return c.direct.DoNoiseRequest(req)
  698. }
  699. // GetSingleUseNoiseRoundTripper returns a RoundTripper that can be only be used
  700. // once (and must be used once) to make a single HTTP request over the noise
  701. // channel to the coordination server.
  702. //
  703. // In addition to the RoundTripper, it returns the HTTP/2 channel's early noise
  704. // payload, if any.
  705. func (c *Auto) GetSingleUseNoiseRoundTripper(ctx context.Context) (http.RoundTripper, *tailcfg.EarlyNoise, error) {
  706. return c.direct.GetSingleUseNoiseRoundTripper(ctx)
  707. }