direct.go 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275
  1. // Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package controlclient
  5. import (
  6. "bytes"
  7. "context"
  8. "crypto/rand"
  9. "encoding/binary"
  10. "encoding/json"
  11. "errors"
  12. "flag"
  13. "fmt"
  14. "io"
  15. "io/ioutil"
  16. "log"
  17. "net/http"
  18. "net/url"
  19. "os"
  20. "os/exec"
  21. "path/filepath"
  22. "reflect"
  23. "runtime"
  24. "strconv"
  25. "strings"
  26. "sync"
  27. "sync/atomic"
  28. "time"
  29. "golang.org/x/crypto/nacl/box"
  30. "inet.af/netaddr"
  31. "tailscale.com/health"
  32. "tailscale.com/ipn/ipnstate"
  33. "tailscale.com/log/logheap"
  34. "tailscale.com/net/dnscache"
  35. "tailscale.com/net/dnsfallback"
  36. "tailscale.com/net/interfaces"
  37. "tailscale.com/net/netns"
  38. "tailscale.com/net/tlsdial"
  39. "tailscale.com/net/tshttpproxy"
  40. "tailscale.com/tailcfg"
  41. "tailscale.com/types/logger"
  42. "tailscale.com/types/netmap"
  43. "tailscale.com/types/opt"
  44. "tailscale.com/types/persist"
  45. "tailscale.com/types/wgkey"
  46. "tailscale.com/util/dnsname"
  47. "tailscale.com/util/systemd"
  48. "tailscale.com/version"
  49. "tailscale.com/wgengine/monitor"
  50. )
  51. // Direct is the client that connects to a tailcontrol server for a node.
  52. type Direct struct {
  53. httpc *http.Client // HTTP client used to talk to tailcontrol
  54. serverURL string // URL of the tailcontrol server
  55. timeNow func() time.Time
  56. lastPrintMap time.Time
  57. newDecompressor func() (Decompressor, error)
  58. keepAlive bool
  59. logf logger.Logf
  60. linkMon *monitor.Mon // or nil
  61. discoPubKey tailcfg.DiscoKey
  62. getMachinePrivKey func() (wgkey.Private, error)
  63. debugFlags []string
  64. keepSharerAndUserSplit bool
  65. skipIPForwardingCheck bool
  66. pinger Pinger
  67. mu sync.Mutex // mutex guards the following fields
  68. serverKey wgkey.Key
  69. persist persist.Persist
  70. authKey string
  71. tryingNewKey wgkey.Private
  72. expiry *time.Time
  73. // hostinfo is mutated in-place while mu is held.
  74. hostinfo *tailcfg.Hostinfo // always non-nil
  75. endpoints []tailcfg.Endpoint
  76. everEndpoints bool // whether we've ever had non-empty endpoints
  77. localPort uint16 // or zero to mean auto
  78. }
  79. type Options struct {
  80. Persist persist.Persist // initial persistent data
  81. GetMachinePrivateKey func() (wgkey.Private, error) // returns the machine key to use
  82. ServerURL string // URL of the tailcontrol server
  83. AuthKey string // optional node auth key for auto registration
  84. TimeNow func() time.Time // time.Now implementation used by Client
  85. Hostinfo *tailcfg.Hostinfo // non-nil passes ownership, nil means to use default using os.Hostname, etc
  86. DiscoPublicKey tailcfg.DiscoKey
  87. NewDecompressor func() (Decompressor, error)
  88. KeepAlive bool
  89. Logf logger.Logf
  90. HTTPTestClient *http.Client // optional HTTP client to use (for tests only)
  91. DebugFlags []string // debug settings to send to control
  92. LinkMonitor *monitor.Mon // optional link monitor
  93. // KeepSharerAndUserSplit controls whether the client
  94. // understands Node.Sharer. If false, the Sharer is mapped to the User.
  95. KeepSharerAndUserSplit bool
  96. // SkipIPForwardingCheck declares that the host's IP
  97. // forwarding works and should not be double-checked by the
  98. // controlclient package.
  99. SkipIPForwardingCheck bool
  100. // Pinger optionally specifies the Pinger to use to satisfy
  101. // MapResponse.PingRequest queries from the control plane.
  102. // If nil, PingRequest queries are not answered.
  103. Pinger Pinger
  104. }
  105. // Pinger is a subset of the wgengine.Engine interface, containing just the Ping method.
  106. type Pinger interface {
  107. // Ping is a request to start a discovery or TSMP ping with the peer handling
  108. // the given IP and then call cb with its ping latency & method.
  109. Ping(ip netaddr.IP, useTSMP bool, cb func(*ipnstate.PingResult))
  110. }
  111. type Decompressor interface {
  112. DecodeAll(input, dst []byte) ([]byte, error)
  113. Close()
  114. }
  115. // NewDirect returns a new Direct client.
  116. func NewDirect(opts Options) (*Direct, error) {
  117. if opts.ServerURL == "" {
  118. return nil, errors.New("controlclient.New: no server URL specified")
  119. }
  120. if opts.GetMachinePrivateKey == nil {
  121. return nil, errors.New("controlclient.New: no GetMachinePrivateKey specified")
  122. }
  123. opts.ServerURL = strings.TrimRight(opts.ServerURL, "/")
  124. serverURL, err := url.Parse(opts.ServerURL)
  125. if err != nil {
  126. return nil, err
  127. }
  128. if opts.TimeNow == nil {
  129. opts.TimeNow = time.Now
  130. }
  131. if opts.Logf == nil {
  132. // TODO(apenwarr): remove this default and fail instead.
  133. // TODO(bradfitz): ... but then it shouldn't be in Options.
  134. opts.Logf = log.Printf
  135. }
  136. httpc := opts.HTTPTestClient
  137. if httpc == nil {
  138. dnsCache := &dnscache.Resolver{
  139. Forward: dnscache.Get().Forward, // use default cache's forwarder
  140. UseLastGood: true,
  141. LookupIPFallback: dnsfallback.Lookup,
  142. }
  143. dialer := netns.NewDialer()
  144. tr := http.DefaultTransport.(*http.Transport).Clone()
  145. tr.Proxy = tshttpproxy.ProxyFromEnvironment
  146. tshttpproxy.SetTransportGetProxyConnectHeader(tr)
  147. tr.TLSClientConfig = tlsdial.Config(serverURL.Hostname(), tr.TLSClientConfig)
  148. tr.DialContext = dnscache.Dialer(dialer.DialContext, dnsCache)
  149. tr.DialTLSContext = dnscache.TLSDialer(dialer.DialContext, dnsCache, tr.TLSClientConfig)
  150. tr.ForceAttemptHTTP2 = true
  151. httpc = &http.Client{Transport: tr}
  152. }
  153. c := &Direct{
  154. httpc: httpc,
  155. getMachinePrivKey: opts.GetMachinePrivateKey,
  156. serverURL: opts.ServerURL,
  157. timeNow: opts.TimeNow,
  158. logf: opts.Logf,
  159. newDecompressor: opts.NewDecompressor,
  160. keepAlive: opts.KeepAlive,
  161. persist: opts.Persist,
  162. authKey: opts.AuthKey,
  163. discoPubKey: opts.DiscoPublicKey,
  164. debugFlags: opts.DebugFlags,
  165. keepSharerAndUserSplit: opts.KeepSharerAndUserSplit,
  166. linkMon: opts.LinkMonitor,
  167. skipIPForwardingCheck: opts.SkipIPForwardingCheck,
  168. pinger: opts.Pinger,
  169. }
  170. if opts.Hostinfo == nil {
  171. c.SetHostinfo(NewHostinfo())
  172. } else {
  173. c.SetHostinfo(opts.Hostinfo)
  174. }
  175. return c, nil
  176. }
  177. var osVersion func() string // non-nil on some platforms
  178. func NewHostinfo() *tailcfg.Hostinfo {
  179. hostname, _ := os.Hostname()
  180. hostname = dnsname.FirstLabel(hostname)
  181. var osv string
  182. if osVersion != nil {
  183. osv = osVersion()
  184. }
  185. return &tailcfg.Hostinfo{
  186. IPNVersion: version.Long,
  187. Hostname: hostname,
  188. OS: version.OS(),
  189. OSVersion: osv,
  190. Package: packageType(),
  191. GoArch: runtime.GOARCH,
  192. }
  193. }
  194. func packageType() string {
  195. switch runtime.GOOS {
  196. case "windows":
  197. if _, err := os.Stat(`C:\ProgramData\chocolatey\lib\tailscale`); err == nil {
  198. return "choco"
  199. }
  200. case "darwin":
  201. // Using tailscaled or IPNExtension?
  202. exe, _ := os.Executable()
  203. return filepath.Base(exe)
  204. }
  205. return ""
  206. }
  207. // SetHostinfo clones the provided Hostinfo and remembers it for the
  208. // next update. It reports whether the Hostinfo has changed.
  209. func (c *Direct) SetHostinfo(hi *tailcfg.Hostinfo) bool {
  210. if hi == nil {
  211. panic("nil Hostinfo")
  212. }
  213. c.mu.Lock()
  214. defer c.mu.Unlock()
  215. if hi.Equal(c.hostinfo) {
  216. return false
  217. }
  218. c.hostinfo = hi.Clone()
  219. j, _ := json.Marshal(c.hostinfo)
  220. c.logf("HostInfo: %s", j)
  221. return true
  222. }
  223. // SetNetInfo clones the provided NetInfo and remembers it for the
  224. // next update. It reports whether the NetInfo has changed.
  225. func (c *Direct) SetNetInfo(ni *tailcfg.NetInfo) bool {
  226. if ni == nil {
  227. panic("nil NetInfo")
  228. }
  229. c.mu.Lock()
  230. defer c.mu.Unlock()
  231. if c.hostinfo == nil {
  232. c.logf("[unexpected] SetNetInfo called with no HostInfo; ignoring NetInfo update: %+v", ni)
  233. return false
  234. }
  235. if reflect.DeepEqual(ni, c.hostinfo.NetInfo) {
  236. return false
  237. }
  238. c.hostinfo.NetInfo = ni.Clone()
  239. return true
  240. }
  241. func (c *Direct) GetPersist() persist.Persist {
  242. c.mu.Lock()
  243. defer c.mu.Unlock()
  244. return c.persist
  245. }
  246. func (c *Direct) TryLogout(ctx context.Context) error {
  247. c.logf("direct.TryLogout()")
  248. mustRegen, newURL, err := c.doLogin(ctx, loginOpt{Logout: true})
  249. c.logf("TryLogout control response: mustRegen=%v, newURL=%v, err=%v", mustRegen, newURL, err)
  250. c.mu.Lock()
  251. c.persist = persist.Persist{}
  252. c.mu.Unlock()
  253. return err
  254. }
  255. func (c *Direct) TryLogin(ctx context.Context, t *tailcfg.Oauth2Token, flags LoginFlags) (url string, err error) {
  256. c.logf("direct.TryLogin(token=%v, flags=%v)", t != nil, flags)
  257. return c.doLoginOrRegen(ctx, loginOpt{Token: t, Flags: flags})
  258. }
  259. // WaitLoginURL sits in a long poll waiting for the user to authenticate at url.
  260. //
  261. // On success, newURL and err will both be nil.
  262. func (c *Direct) WaitLoginURL(ctx context.Context, url string) (newURL string, err error) {
  263. c.logf("direct.WaitLoginURL")
  264. return c.doLoginOrRegen(ctx, loginOpt{URL: url})
  265. }
  266. func (c *Direct) doLoginOrRegen(ctx context.Context, opt loginOpt) (newURL string, err error) {
  267. mustRegen, url, err := c.doLogin(ctx, opt)
  268. if err != nil {
  269. return url, err
  270. }
  271. if mustRegen {
  272. opt.Regen = true
  273. _, url, err = c.doLogin(ctx, opt)
  274. }
  275. return url, err
  276. }
  277. type loginOpt struct {
  278. Token *tailcfg.Oauth2Token
  279. Flags LoginFlags
  280. Regen bool
  281. URL string
  282. Logout bool
  283. }
  284. func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, newURL string, err error) {
  285. c.mu.Lock()
  286. persist := c.persist
  287. tryingNewKey := c.tryingNewKey
  288. serverKey := c.serverKey
  289. authKey := c.authKey
  290. hostinfo := c.hostinfo.Clone()
  291. backendLogID := hostinfo.BackendLogID
  292. expired := c.expiry != nil && !c.expiry.IsZero() && c.expiry.Before(c.timeNow())
  293. c.mu.Unlock()
  294. machinePrivKey, err := c.getMachinePrivKey()
  295. if err != nil {
  296. return false, "", fmt.Errorf("getMachinePrivKey: %w", err)
  297. }
  298. if machinePrivKey.IsZero() {
  299. return false, "", errors.New("getMachinePrivKey returned zero key")
  300. }
  301. regen := opt.Regen
  302. if opt.Logout {
  303. c.logf("logging out...")
  304. } else {
  305. if expired {
  306. c.logf("Old key expired -> regen=true")
  307. systemd.Status("key expired; run 'tailscale up' to authenticate")
  308. regen = true
  309. }
  310. if (opt.Flags & LoginInteractive) != 0 {
  311. c.logf("LoginInteractive -> regen=true")
  312. regen = true
  313. }
  314. }
  315. c.logf("doLogin(regen=%v, hasUrl=%v)", regen, opt.URL != "")
  316. if serverKey.IsZero() {
  317. var err error
  318. serverKey, err = loadServerKey(ctx, c.httpc, c.serverURL)
  319. if err != nil {
  320. return regen, opt.URL, err
  321. }
  322. c.mu.Lock()
  323. c.serverKey = serverKey
  324. c.mu.Unlock()
  325. }
  326. var oldNodeKey wgkey.Key
  327. switch {
  328. case opt.Logout:
  329. tryingNewKey = persist.PrivateNodeKey
  330. case opt.URL != "":
  331. // Nothing.
  332. case regen || persist.PrivateNodeKey.IsZero():
  333. c.logf("Generating a new nodekey.")
  334. persist.OldPrivateNodeKey = persist.PrivateNodeKey
  335. key, err := wgkey.NewPrivate()
  336. if err != nil {
  337. c.logf("login keygen: %v", err)
  338. return regen, opt.URL, err
  339. }
  340. tryingNewKey = key
  341. default:
  342. // Try refreshing the current key first
  343. tryingNewKey = persist.PrivateNodeKey
  344. }
  345. if !persist.OldPrivateNodeKey.IsZero() {
  346. oldNodeKey = persist.OldPrivateNodeKey.Public()
  347. }
  348. if tryingNewKey.IsZero() {
  349. if opt.Logout {
  350. return false, "", errors.New("no nodekey to log out")
  351. }
  352. log.Fatalf("tryingNewKey is empty, give up")
  353. }
  354. if backendLogID == "" {
  355. err = errors.New("hostinfo: BackendLogID missing")
  356. return regen, opt.URL, err
  357. }
  358. now := time.Now().Round(time.Second)
  359. request := tailcfg.RegisterRequest{
  360. Version: 1,
  361. OldNodeKey: tailcfg.NodeKey(oldNodeKey),
  362. NodeKey: tailcfg.NodeKey(tryingNewKey.Public()),
  363. Hostinfo: hostinfo,
  364. Followup: opt.URL,
  365. Timestamp: &now,
  366. }
  367. if opt.Logout {
  368. request.Expiry = time.Unix(123, 0) // far in the past
  369. }
  370. c.logf("RegisterReq: onode=%v node=%v fup=%v",
  371. request.OldNodeKey.ShortString(),
  372. request.NodeKey.ShortString(), opt.URL != "")
  373. request.Auth.Oauth2Token = opt.Token
  374. request.Auth.Provider = persist.Provider
  375. request.Auth.LoginName = persist.LoginName
  376. request.Auth.AuthKey = authKey
  377. err = signRegisterRequest(&request, c.serverURL, c.serverKey, machinePrivKey.Public())
  378. if err != nil {
  379. // If signing failed, clear all related fields
  380. request.SignatureType = tailcfg.SignatureNone
  381. request.Timestamp = nil
  382. request.DeviceCert = nil
  383. request.Signature = nil
  384. // Don't log the common error types. Signatures are not usually enabled,
  385. // so these are expected.
  386. if !errors.Is(err, errCertificateNotConfigured) && !errors.Is(err, errNoCertStore) {
  387. c.logf("RegisterReq sign error: %v", err)
  388. }
  389. }
  390. if debugRegister {
  391. j, _ := json.MarshalIndent(request, "", "\t")
  392. c.logf("RegisterRequest: %s", j)
  393. }
  394. bodyData, err := encode(request, &serverKey, &machinePrivKey)
  395. if err != nil {
  396. return regen, opt.URL, err
  397. }
  398. body := bytes.NewReader(bodyData)
  399. u := fmt.Sprintf("%s/machine/%s", c.serverURL, machinePrivKey.Public().HexString())
  400. req, err := http.NewRequest("POST", u, body)
  401. if err != nil {
  402. return regen, opt.URL, err
  403. }
  404. req = req.WithContext(ctx)
  405. res, err := c.httpc.Do(req)
  406. if err != nil {
  407. return regen, opt.URL, fmt.Errorf("register request: %v", err)
  408. }
  409. if res.StatusCode != 200 {
  410. msg, _ := ioutil.ReadAll(res.Body)
  411. res.Body.Close()
  412. return regen, opt.URL, fmt.Errorf("register request: http %d: %.200s",
  413. res.StatusCode, strings.TrimSpace(string(msg)))
  414. }
  415. resp := tailcfg.RegisterResponse{}
  416. if err := decode(res, &resp, &serverKey, &machinePrivKey); err != nil {
  417. c.logf("error decoding RegisterResponse with server key %s and machine key %s: %v", serverKey, machinePrivKey.Public(), err)
  418. return regen, opt.URL, fmt.Errorf("register request: %v", err)
  419. }
  420. if debugRegister {
  421. j, _ := json.MarshalIndent(resp, "", "\t")
  422. c.logf("RegisterResponse: %s", j)
  423. }
  424. // Log without PII:
  425. c.logf("RegisterReq: got response; nodeKeyExpired=%v, machineAuthorized=%v; authURL=%v",
  426. resp.NodeKeyExpired, resp.MachineAuthorized, resp.AuthURL != "")
  427. if resp.NodeKeyExpired {
  428. if regen {
  429. return true, "", fmt.Errorf("weird: regen=true but server says NodeKeyExpired: %v", request.NodeKey)
  430. }
  431. c.logf("server reports new node key %v has expired",
  432. request.NodeKey.ShortString())
  433. return true, "", nil
  434. }
  435. if resp.Login.Provider != "" {
  436. persist.Provider = resp.Login.Provider
  437. }
  438. if resp.Login.LoginName != "" {
  439. persist.LoginName = resp.Login.LoginName
  440. }
  441. // TODO(crawshaw): RegisterResponse should be able to mechanically
  442. // communicate some extra instructions from the server:
  443. // - new node key required
  444. // - machine key no longer supported
  445. // - user is disabled
  446. if resp.AuthURL != "" {
  447. c.logf("AuthURL is %v", resp.AuthURL)
  448. } else {
  449. c.logf("No AuthURL")
  450. }
  451. c.mu.Lock()
  452. if resp.AuthURL == "" {
  453. // key rotation is complete
  454. persist.PrivateNodeKey = tryingNewKey
  455. } else {
  456. // save it for the retry-with-URL
  457. c.tryingNewKey = tryingNewKey
  458. }
  459. c.persist = persist
  460. c.mu.Unlock()
  461. if err != nil {
  462. return regen, "", err
  463. }
  464. if ctx.Err() != nil {
  465. return regen, "", ctx.Err()
  466. }
  467. return false, resp.AuthURL, nil
  468. }
  469. func sameEndpoints(a, b []tailcfg.Endpoint) bool {
  470. if len(a) != len(b) {
  471. return false
  472. }
  473. for i := range a {
  474. if a[i] != b[i] {
  475. return false
  476. }
  477. }
  478. return true
  479. }
  480. // newEndpoints acquires c.mu and sets the local port and endpoints and reports
  481. // whether they've changed.
  482. //
  483. // It does not retain the provided slice.
  484. func (c *Direct) newEndpoints(localPort uint16, endpoints []tailcfg.Endpoint) (changed bool) {
  485. c.mu.Lock()
  486. defer c.mu.Unlock()
  487. // Nothing new?
  488. if c.localPort == localPort && sameEndpoints(c.endpoints, endpoints) {
  489. return false // unchanged
  490. }
  491. var epStrs []string
  492. for _, ep := range endpoints {
  493. epStrs = append(epStrs, ep.Addr.String())
  494. }
  495. c.logf("client.newEndpoints(%v, %v)", localPort, epStrs)
  496. c.localPort = localPort
  497. c.endpoints = append(c.endpoints[:0], endpoints...)
  498. if len(endpoints) > 0 {
  499. c.everEndpoints = true
  500. }
  501. return true // changed
  502. }
  503. // SetEndpoints updates the list of locally advertised endpoints.
  504. // It won't be replicated to the server until a *fresh* call to PollNetMap().
  505. // You don't need to restart PollNetMap if we return changed==false.
  506. func (c *Direct) SetEndpoints(localPort uint16, endpoints []tailcfg.Endpoint) (changed bool) {
  507. // (no log message on function entry, because it clutters the logs
  508. // if endpoints haven't changed. newEndpoints() will log it.)
  509. return c.newEndpoints(localPort, endpoints)
  510. }
  511. func inTest() bool { return flag.Lookup("test.v") != nil }
  512. // PollNetMap makes a /map request to download the network map, calling cb with
  513. // each new netmap.
  514. //
  515. // maxPolls is how many network maps to download; common values are 1
  516. // or -1 (to keep a long-poll query open to the server).
  517. func (c *Direct) PollNetMap(ctx context.Context, maxPolls int, cb func(*netmap.NetworkMap)) error {
  518. return c.sendMapRequest(ctx, maxPolls, cb)
  519. }
  520. // SendLiteMapUpdate makes a /map request to update the server of our latest state,
  521. // but does not fetch anything. It returns an error if the server did not return a
  522. // successful 200 OK response.
  523. func (c *Direct) SendLiteMapUpdate(ctx context.Context) error {
  524. return c.sendMapRequest(ctx, 1, nil)
  525. }
  526. // If we go more than pollTimeout without hearing from the server,
  527. // end the long poll. We should be receiving a keep alive ping
  528. // every minute.
  529. const pollTimeout = 120 * time.Second
  530. // cb nil means to omit peers.
  531. func (c *Direct) sendMapRequest(ctx context.Context, maxPolls int, cb func(*netmap.NetworkMap)) error {
  532. c.mu.Lock()
  533. persist := c.persist
  534. serverURL := c.serverURL
  535. serverKey := c.serverKey
  536. hostinfo := c.hostinfo.Clone()
  537. backendLogID := hostinfo.BackendLogID
  538. localPort := c.localPort
  539. var epStrs []string
  540. var epTypes []tailcfg.EndpointType
  541. for _, ep := range c.endpoints {
  542. epStrs = append(epStrs, ep.Addr.String())
  543. epTypes = append(epTypes, ep.Type)
  544. }
  545. everEndpoints := c.everEndpoints
  546. c.mu.Unlock()
  547. machinePrivKey, err := c.getMachinePrivKey()
  548. if err != nil {
  549. return fmt.Errorf("getMachinePrivKey: %w", err)
  550. }
  551. if machinePrivKey.IsZero() {
  552. return errors.New("getMachinePrivKey returned zero key")
  553. }
  554. if persist.PrivateNodeKey.IsZero() {
  555. return errors.New("privateNodeKey is zero")
  556. }
  557. if backendLogID == "" {
  558. return errors.New("hostinfo: BackendLogID missing")
  559. }
  560. allowStream := maxPolls != 1
  561. c.logf("[v1] PollNetMap: stream=%v :%v ep=%v", allowStream, localPort, epStrs)
  562. vlogf := logger.Discard
  563. if Debug.NetMap {
  564. // TODO(bradfitz): update this to use "[v2]" prefix perhaps? but we don't
  565. // want to upload it always.
  566. vlogf = c.logf
  567. }
  568. request := &tailcfg.MapRequest{
  569. Version: tailcfg.CurrentMapRequestVersion,
  570. KeepAlive: c.keepAlive,
  571. NodeKey: tailcfg.NodeKey(persist.PrivateNodeKey.Public()),
  572. DiscoKey: c.discoPubKey,
  573. Endpoints: epStrs,
  574. EndpointTypes: epTypes,
  575. Stream: allowStream,
  576. Hostinfo: hostinfo,
  577. DebugFlags: c.debugFlags,
  578. OmitPeers: cb == nil,
  579. }
  580. var extraDebugFlags []string
  581. if hostinfo != nil && c.linkMon != nil && !c.skipIPForwardingCheck &&
  582. ipForwardingBroken(hostinfo.RoutableIPs, c.linkMon.InterfaceState()) {
  583. extraDebugFlags = append(extraDebugFlags, "warn-ip-forwarding-off")
  584. }
  585. if health.RouterHealth() != nil {
  586. extraDebugFlags = append(extraDebugFlags, "warn-router-unhealthy")
  587. }
  588. if health.NetworkCategoryHealth() != nil {
  589. extraDebugFlags = append(extraDebugFlags, "warn-network-category-unhealthy")
  590. }
  591. if len(extraDebugFlags) > 0 {
  592. old := request.DebugFlags
  593. request.DebugFlags = append(old[:len(old):len(old)], extraDebugFlags...)
  594. }
  595. if c.newDecompressor != nil {
  596. request.Compress = "zstd"
  597. }
  598. // On initial startup before we know our endpoints, set the ReadOnly flag
  599. // to tell the control server not to distribute out our (empty) endpoints to peers.
  600. // Presumably we'll learn our endpoints in a half second and do another post
  601. // with useful results. The first POST just gets us the DERP map which we
  602. // need to do the STUN queries to discover our endpoints.
  603. // TODO(bradfitz): we skip this optimization in tests, though,
  604. // because the e2e tests are currently hyperspecific about the
  605. // ordering of things. The e2e tests need love.
  606. if len(epStrs) == 0 && !everEndpoints && !inTest() {
  607. request.ReadOnly = true
  608. }
  609. bodyData, err := encode(request, &serverKey, &machinePrivKey)
  610. if err != nil {
  611. vlogf("netmap: encode: %v", err)
  612. return err
  613. }
  614. ctx, cancel := context.WithCancel(ctx)
  615. defer cancel()
  616. machinePubKey := tailcfg.MachineKey(machinePrivKey.Public())
  617. t0 := time.Now()
  618. u := fmt.Sprintf("%s/machine/%s/map", serverURL, machinePubKey.HexString())
  619. req, err := http.NewRequestWithContext(ctx, "POST", u, bytes.NewReader(bodyData))
  620. if err != nil {
  621. return err
  622. }
  623. res, err := c.httpc.Do(req)
  624. if err != nil {
  625. vlogf("netmap: Do: %v", err)
  626. return err
  627. }
  628. vlogf("netmap: Do = %v after %v", res.StatusCode, time.Since(t0).Round(time.Millisecond))
  629. if res.StatusCode != 200 {
  630. msg, _ := ioutil.ReadAll(res.Body)
  631. res.Body.Close()
  632. return fmt.Errorf("initial fetch failed %d: %.200s",
  633. res.StatusCode, strings.TrimSpace(string(msg)))
  634. }
  635. defer res.Body.Close()
  636. health.NoteMapRequestHeard(request)
  637. if cb == nil {
  638. io.Copy(ioutil.Discard, res.Body)
  639. return nil
  640. }
  641. timeout := time.NewTimer(pollTimeout)
  642. timeoutReset := make(chan struct{})
  643. pollDone := make(chan struct{})
  644. defer close(pollDone)
  645. go func() {
  646. for {
  647. select {
  648. case <-pollDone:
  649. vlogf("netmap: ending timeout goroutine")
  650. return
  651. case <-timeout.C:
  652. c.logf("map response long-poll timed out!")
  653. cancel()
  654. return
  655. case <-timeoutReset:
  656. if !timeout.Stop() {
  657. select {
  658. case <-timeout.C:
  659. case <-pollDone:
  660. vlogf("netmap: ending timeout goroutine")
  661. return
  662. }
  663. }
  664. vlogf("netmap: reset timeout timer")
  665. timeout.Reset(pollTimeout)
  666. }
  667. }
  668. }()
  669. sess := newMapSession(persist.PrivateNodeKey)
  670. sess.logf = c.logf
  671. sess.vlogf = vlogf
  672. sess.machinePubKey = machinePubKey
  673. sess.keepSharerAndUserSplit = c.keepSharerAndUserSplit
  674. // If allowStream, then the server will use an HTTP long poll to
  675. // return incremental results. There is always one response right
  676. // away, followed by a delay, and eventually others.
  677. // If !allowStream, it'll still send the first result in exactly
  678. // the same format before just closing the connection.
  679. // We can use this same read loop either way.
  680. var msg []byte
  681. for i := 0; i < maxPolls || maxPolls < 0; i++ {
  682. vlogf("netmap: starting size read after %v (poll %v)", time.Since(t0).Round(time.Millisecond), i)
  683. var siz [4]byte
  684. if _, err := io.ReadFull(res.Body, siz[:]); err != nil {
  685. vlogf("netmap: size read error after %v: %v", time.Since(t0).Round(time.Millisecond), err)
  686. return err
  687. }
  688. size := binary.LittleEndian.Uint32(siz[:])
  689. vlogf("netmap: read size %v after %v", size, time.Since(t0).Round(time.Millisecond))
  690. msg = append(msg[:0], make([]byte, size)...)
  691. if _, err := io.ReadFull(res.Body, msg); err != nil {
  692. vlogf("netmap: body read error: %v", err)
  693. return err
  694. }
  695. vlogf("netmap: read body after %v", time.Since(t0).Round(time.Millisecond))
  696. var resp tailcfg.MapResponse
  697. if err := c.decodeMsg(msg, &resp, &machinePrivKey); err != nil {
  698. vlogf("netmap: decode error: %v")
  699. return err
  700. }
  701. if allowStream {
  702. health.GotStreamedMapResponse()
  703. }
  704. if pr := resp.PingRequest; pr != nil {
  705. go answerPing(c.logf, c.httpc, pr)
  706. }
  707. if resp.KeepAlive {
  708. vlogf("netmap: got keep-alive")
  709. } else {
  710. vlogf("netmap: got new map")
  711. }
  712. select {
  713. case timeoutReset <- struct{}{}:
  714. vlogf("netmap: sent timer reset")
  715. case <-ctx.Done():
  716. c.logf("[v1] netmap: not resetting timer; context done: %v", ctx.Err())
  717. return ctx.Err()
  718. }
  719. if resp.KeepAlive {
  720. continue
  721. }
  722. if resp.Debug != nil {
  723. if resp.Debug.LogHeapPprof {
  724. go logheap.LogHeap(resp.Debug.LogHeapURL)
  725. }
  726. if resp.Debug.GoroutineDumpURL != "" {
  727. go dumpGoroutinesToURL(c.httpc, resp.Debug.GoroutineDumpURL)
  728. }
  729. setControlAtomic(&controlUseDERPRoute, resp.Debug.DERPRoute)
  730. setControlAtomic(&controlTrimWGConfig, resp.Debug.TrimWGConfig)
  731. if sleep := time.Duration(resp.Debug.SleepSeconds * float64(time.Second)); sleep > 0 {
  732. if err := sleepAsRequested(ctx, c.logf, timeoutReset, sleep); err != nil {
  733. return err
  734. }
  735. }
  736. }
  737. nm := sess.netmapForResponse(&resp)
  738. if nm.SelfNode == nil {
  739. c.logf("MapResponse lacked node")
  740. return errors.New("MapResponse lacked node")
  741. }
  742. // Temporarily (2020-06-29) support removing all but
  743. // discovery-supporting nodes during development, for
  744. // less noise.
  745. if Debug.OnlyDisco {
  746. anyOld, numDisco := false, 0
  747. for _, p := range nm.Peers {
  748. if p.DiscoKey.IsZero() {
  749. anyOld = true
  750. } else {
  751. numDisco++
  752. }
  753. }
  754. if anyOld {
  755. filtered := make([]*tailcfg.Node, 0, numDisco)
  756. for _, p := range nm.Peers {
  757. if !p.DiscoKey.IsZero() {
  758. filtered = append(filtered, p)
  759. }
  760. }
  761. nm.Peers = filtered
  762. }
  763. }
  764. if Debug.StripEndpoints {
  765. for _, p := range resp.Peers {
  766. // We need at least one endpoint here for now else
  767. // other code doesn't even create the discoEndpoint.
  768. // TODO(bradfitz): fix that and then just nil this out.
  769. p.Endpoints = []string{"127.9.9.9:456"}
  770. }
  771. }
  772. if Debug.StripCaps {
  773. nm.SelfNode.Capabilities = nil
  774. }
  775. // Get latest localPort. This might've changed if
  776. // a lite map update occured meanwhile. This only affects
  777. // the end-to-end test.
  778. // TODO(bradfitz): remove the NetworkMap.LocalPort field entirely.
  779. c.mu.Lock()
  780. nm.LocalPort = c.localPort
  781. c.mu.Unlock()
  782. // Printing the netmap can be extremely verbose, but is very
  783. // handy for debugging. Let's limit how often we do it.
  784. // Code elsewhere prints netmap diffs every time, so this
  785. // occasional full dump, plus incremental diffs, should do
  786. // the job.
  787. now := c.timeNow()
  788. if now.Sub(c.lastPrintMap) >= 5*time.Minute {
  789. c.lastPrintMap = now
  790. c.logf("[v1] new network map[%d]:\n%s", i, nm.Concise())
  791. }
  792. c.mu.Lock()
  793. c.expiry = &nm.Expiry
  794. c.mu.Unlock()
  795. cb(nm)
  796. }
  797. if ctx.Err() != nil {
  798. return ctx.Err()
  799. }
  800. return nil
  801. }
  802. func decode(res *http.Response, v interface{}, serverKey *wgkey.Key, mkey *wgkey.Private) error {
  803. defer res.Body.Close()
  804. msg, err := ioutil.ReadAll(io.LimitReader(res.Body, 1<<20))
  805. if err != nil {
  806. return err
  807. }
  808. if res.StatusCode != 200 {
  809. return fmt.Errorf("%d: %v", res.StatusCode, string(msg))
  810. }
  811. return decodeMsg(msg, v, serverKey, mkey)
  812. }
  813. var (
  814. debugMap, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_MAP"))
  815. debugRegister, _ = strconv.ParseBool(os.Getenv("TS_DEBUG_REGISTER"))
  816. )
  817. var jsonEscapedZero = []byte(`\u0000`)
  818. func (c *Direct) decodeMsg(msg []byte, v interface{}, machinePrivKey *wgkey.Private) error {
  819. c.mu.Lock()
  820. serverKey := c.serverKey
  821. c.mu.Unlock()
  822. decrypted, err := decryptMsg(msg, &serverKey, machinePrivKey)
  823. if err != nil {
  824. return err
  825. }
  826. var b []byte
  827. if c.newDecompressor == nil {
  828. b = decrypted
  829. } else {
  830. decoder, err := c.newDecompressor()
  831. if err != nil {
  832. return err
  833. }
  834. defer decoder.Close()
  835. b, err = decoder.DecodeAll(decrypted, nil)
  836. if err != nil {
  837. return err
  838. }
  839. }
  840. if debugMap {
  841. var buf bytes.Buffer
  842. json.Indent(&buf, b, "", " ")
  843. log.Printf("MapResponse: %s", buf.Bytes())
  844. }
  845. if bytes.Contains(b, jsonEscapedZero) {
  846. log.Printf("[unexpected] zero byte in controlclient.Direct.decodeMsg into %T: %q", v, b)
  847. }
  848. if err := json.Unmarshal(b, v); err != nil {
  849. return fmt.Errorf("response: %v", err)
  850. }
  851. return nil
  852. }
  853. func decodeMsg(msg []byte, v interface{}, serverKey *wgkey.Key, machinePrivKey *wgkey.Private) error {
  854. decrypted, err := decryptMsg(msg, serverKey, machinePrivKey)
  855. if err != nil {
  856. return err
  857. }
  858. if bytes.Contains(decrypted, jsonEscapedZero) {
  859. log.Printf("[unexpected] zero byte in controlclient decodeMsg into %T: %q", v, decrypted)
  860. }
  861. if err := json.Unmarshal(decrypted, v); err != nil {
  862. return fmt.Errorf("response: %v", err)
  863. }
  864. return nil
  865. }
  866. func decryptMsg(msg []byte, serverKey *wgkey.Key, mkey *wgkey.Private) ([]byte, error) {
  867. var nonce [24]byte
  868. if len(msg) < len(nonce)+1 {
  869. return nil, fmt.Errorf("response missing nonce, len=%d", len(msg))
  870. }
  871. copy(nonce[:], msg)
  872. msg = msg[len(nonce):]
  873. pub, pri := (*[32]byte)(serverKey), (*[32]byte)(mkey)
  874. decrypted, ok := box.Open(nil, msg, &nonce, pub, pri)
  875. if !ok {
  876. return nil, fmt.Errorf("cannot decrypt response (len %d + nonce %d = %d)", len(msg), len(nonce), len(msg)+len(nonce))
  877. }
  878. return decrypted, nil
  879. }
  880. func encode(v interface{}, serverKey *wgkey.Key, mkey *wgkey.Private) ([]byte, error) {
  881. b, err := json.Marshal(v)
  882. if err != nil {
  883. return nil, err
  884. }
  885. if debugMap {
  886. if _, ok := v.(*tailcfg.MapRequest); ok {
  887. log.Printf("MapRequest: %s", b)
  888. }
  889. }
  890. var nonce [24]byte
  891. if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
  892. panic(err)
  893. }
  894. pub, pri := (*[32]byte)(serverKey), (*[32]byte)(mkey)
  895. msg := box.Seal(nonce[:], b, &nonce, pub, pri)
  896. return msg, nil
  897. }
  898. func loadServerKey(ctx context.Context, httpc *http.Client, serverURL string) (wgkey.Key, error) {
  899. req, err := http.NewRequest("GET", serverURL+"/key", nil)
  900. if err != nil {
  901. return wgkey.Key{}, fmt.Errorf("create control key request: %v", err)
  902. }
  903. req = req.WithContext(ctx)
  904. res, err := httpc.Do(req)
  905. if err != nil {
  906. return wgkey.Key{}, fmt.Errorf("fetch control key: %v", err)
  907. }
  908. defer res.Body.Close()
  909. b, err := ioutil.ReadAll(io.LimitReader(res.Body, 1<<16))
  910. if err != nil {
  911. return wgkey.Key{}, fmt.Errorf("fetch control key response: %v", err)
  912. }
  913. if res.StatusCode != 200 {
  914. return wgkey.Key{}, fmt.Errorf("fetch control key: %d: %s", res.StatusCode, string(b))
  915. }
  916. key, err := wgkey.ParseHex(string(b))
  917. if err != nil {
  918. return wgkey.Key{}, fmt.Errorf("fetch control key: %v", err)
  919. }
  920. return key, nil
  921. }
  922. // Debug contains temporary internal-only debug knobs.
  923. // They're unexported to not draw attention to them.
  924. var Debug = initDebug()
  925. type debug struct {
  926. NetMap bool
  927. ProxyDNS bool
  928. OnlyDisco bool
  929. Disco bool
  930. StripEndpoints bool // strip endpoints from control (only use disco messages)
  931. StripCaps bool // strip all local node's control-provided capabilities
  932. }
  933. func initDebug() debug {
  934. use := os.Getenv("TS_DEBUG_USE_DISCO")
  935. return debug{
  936. NetMap: envBool("TS_DEBUG_NETMAP"),
  937. ProxyDNS: envBool("TS_DEBUG_PROXY_DNS"),
  938. StripEndpoints: envBool("TS_DEBUG_STRIP_ENDPOINTS"),
  939. StripCaps: envBool("TS_DEBUG_STRIP_CAPS"),
  940. OnlyDisco: use == "only",
  941. Disco: use == "only" || use == "" || envBool("TS_DEBUG_USE_DISCO"),
  942. }
  943. }
  944. func envBool(k string) bool {
  945. e := os.Getenv(k)
  946. if e == "" {
  947. return false
  948. }
  949. v, err := strconv.ParseBool(e)
  950. if err != nil {
  951. panic(fmt.Sprintf("invalid non-bool %q for env var %q", e, k))
  952. }
  953. return v
  954. }
  955. var clockNow = time.Now
  956. // opt.Bool configs from control.
  957. var (
  958. controlUseDERPRoute atomic.Value
  959. controlTrimWGConfig atomic.Value
  960. )
  961. func setControlAtomic(dst *atomic.Value, v opt.Bool) {
  962. old, ok := dst.Load().(opt.Bool)
  963. if !ok || old != v {
  964. dst.Store(v)
  965. }
  966. }
  967. // DERPRouteFlag reports the last reported value from control for whether
  968. // DERP route optimization (Issue 150) should be enabled.
  969. func DERPRouteFlag() opt.Bool {
  970. v, _ := controlUseDERPRoute.Load().(opt.Bool)
  971. return v
  972. }
  973. // TrimWGConfig reports the last reported value from control for whether
  974. // we should do lazy wireguard configuration.
  975. func TrimWGConfig() opt.Bool {
  976. v, _ := controlTrimWGConfig.Load().(opt.Bool)
  977. return v
  978. }
  979. // ipForwardingBroken reports whether the system's IP forwarding is disabled
  980. // and will definitely not work for the routes provided.
  981. //
  982. // It should not return false positives.
  983. //
  984. // TODO(bradfitz): merge this code into LocalBackend.CheckIPForwarding
  985. // and change controlclient.Options.SkipIPForwardingCheck into a
  986. // func([]netaddr.IPPrefix) error signature instead. Then we only have
  987. // one copy of this code.
  988. func ipForwardingBroken(routes []netaddr.IPPrefix, state *interfaces.State) bool {
  989. if len(routes) == 0 {
  990. // Nothing to route, so no need to warn.
  991. return false
  992. }
  993. if runtime.GOOS != "linux" {
  994. // We only do subnet routing on Linux for now.
  995. // It might work on darwin/macOS when building from source, so
  996. // don't return true for other OSes. We can OS-based warnings
  997. // already in the admin panel.
  998. return false
  999. }
  1000. localIPs := map[netaddr.IP]bool{}
  1001. for _, addrs := range state.InterfaceIPs {
  1002. for _, pfx := range addrs {
  1003. localIPs[pfx.IP()] = true
  1004. }
  1005. }
  1006. v4Routes, v6Routes := false, false
  1007. for _, r := range routes {
  1008. // It's possible to advertise a route to one of the local
  1009. // machine's local IPs. IP forwarding isn't required for this
  1010. // to work, so we shouldn't warn for such exports.
  1011. if r.IsSingleIP() && localIPs[r.IP()] {
  1012. continue
  1013. }
  1014. if r.IP().Is4() {
  1015. v4Routes = true
  1016. } else {
  1017. v6Routes = true
  1018. }
  1019. }
  1020. if v4Routes {
  1021. out, err := ioutil.ReadFile("/proc/sys/net/ipv4/ip_forward")
  1022. if err != nil {
  1023. // Try another way.
  1024. out, err = exec.Command("sysctl", "-n", "net.ipv4.ip_forward").Output()
  1025. }
  1026. if err != nil {
  1027. // Oh well, we tried. This is just for debugging.
  1028. // We don't want false positives.
  1029. // TODO: maybe we want a different warning for inability to check?
  1030. return false
  1031. }
  1032. if strings.TrimSpace(string(out)) == "0" {
  1033. return true
  1034. }
  1035. }
  1036. if v6Routes {
  1037. // Note: you might be wondering why we check only the state of
  1038. // conf.all.forwarding, rather than per-interface forwarding
  1039. // configuration. According to kernel documentation, it seems
  1040. // that to actually forward packets, you need to enable
  1041. // forwarding globally, and the per-interface forwarding
  1042. // setting only alters other things such as how router
  1043. // advertisements are handled. The kernel itself warns that
  1044. // enabling forwarding per-interface and not globally will
  1045. // probably not work, so I feel okay calling those configs
  1046. // broken until we have proof otherwise.
  1047. out, err := ioutil.ReadFile("/proc/sys/net/ipv6/conf/all/forwarding")
  1048. if err != nil {
  1049. out, err = exec.Command("sysctl", "-n", "net.ipv6.conf.all.forwarding").Output()
  1050. }
  1051. if err != nil {
  1052. // Oh well, we tried. This is just for debugging.
  1053. // We don't want false positives.
  1054. // TODO: maybe we want a different warning for inability to check?
  1055. return false
  1056. }
  1057. if strings.TrimSpace(string(out)) == "0" {
  1058. return true
  1059. }
  1060. }
  1061. return false
  1062. }
  1063. func answerPing(logf logger.Logf, c *http.Client, pr *tailcfg.PingRequest) {
  1064. if pr.URL == "" {
  1065. logf("invalid PingRequest with no URL")
  1066. return
  1067. }
  1068. ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
  1069. defer cancel()
  1070. req, err := http.NewRequestWithContext(ctx, "HEAD", pr.URL, nil)
  1071. if err != nil {
  1072. logf("http.NewRequestWithContext(%q): %v", pr.URL, err)
  1073. return
  1074. }
  1075. if pr.Log {
  1076. logf("answerPing: sending ping to %v ...", pr.URL)
  1077. }
  1078. t0 := time.Now()
  1079. _, err = c.Do(req)
  1080. d := time.Since(t0).Round(time.Millisecond)
  1081. if err != nil {
  1082. logf("answerPing error: %v to %v (after %v)", err, pr.URL, d)
  1083. } else if pr.Log {
  1084. logf("answerPing complete to %v (after %v)", pr.URL, d)
  1085. }
  1086. }
  1087. func sleepAsRequested(ctx context.Context, logf logger.Logf, timeoutReset chan<- struct{}, d time.Duration) error {
  1088. const maxSleep = 5 * time.Minute
  1089. if d > maxSleep {
  1090. logf("sleeping for %v, capped from server-requested %v ...", maxSleep, d)
  1091. d = maxSleep
  1092. } else {
  1093. logf("sleeping for server-requested %v ...", d)
  1094. }
  1095. ticker := time.NewTicker(pollTimeout / 2)
  1096. defer ticker.Stop()
  1097. timer := time.NewTimer(d)
  1098. defer timer.Stop()
  1099. for {
  1100. select {
  1101. case <-ctx.Done():
  1102. return ctx.Err()
  1103. case <-timer.C:
  1104. return nil
  1105. case <-ticker.C:
  1106. select {
  1107. case timeoutReset <- struct{}{}:
  1108. case <-timer.C:
  1109. return nil
  1110. case <-ctx.Done():
  1111. return ctx.Err()
  1112. }
  1113. }
  1114. }
  1115. }
  1116. // SetDNS sends the SetDNSRequest request to the control plane server,
  1117. // requesting a DNS record be created or updated.
  1118. func (c *Direct) SetDNS(ctx context.Context, req *tailcfg.SetDNSRequest) error {
  1119. c.mu.Lock()
  1120. serverKey := c.serverKey
  1121. c.mu.Unlock()
  1122. if serverKey.IsZero() {
  1123. return errors.New("zero serverKey")
  1124. }
  1125. machinePrivKey, err := c.getMachinePrivKey()
  1126. if err != nil {
  1127. return fmt.Errorf("getMachinePrivKey: %w", err)
  1128. }
  1129. if machinePrivKey.IsZero() {
  1130. return errors.New("getMachinePrivKey returned zero key")
  1131. }
  1132. bodyData, err := encode(req, &serverKey, &machinePrivKey)
  1133. if err != nil {
  1134. return err
  1135. }
  1136. body := bytes.NewReader(bodyData)
  1137. u := fmt.Sprintf("%s/machine/%s/set-dns", c.serverURL, machinePrivKey.Public().HexString())
  1138. hreq, err := http.NewRequestWithContext(ctx, "POST", u, body)
  1139. if err != nil {
  1140. return err
  1141. }
  1142. res, err := c.httpc.Do(hreq)
  1143. if err != nil {
  1144. return err
  1145. }
  1146. defer res.Body.Close()
  1147. if res.StatusCode != 200 {
  1148. msg, _ := ioutil.ReadAll(res.Body)
  1149. return fmt.Errorf("sign-dns response: %v, %.200s", res.Status, strings.TrimSpace(string(msg)))
  1150. }
  1151. var setDNSRes struct{} // no fields yet
  1152. if err := decode(res, &setDNSRes, &serverKey, &machinePrivKey); err != nil {
  1153. c.logf("error decoding SetDNSResponse with server key %s and machine key %s: %v", serverKey, machinePrivKey.Public(), err)
  1154. return fmt.Errorf("set-dns-response: %v", err)
  1155. }
  1156. return nil
  1157. }