map.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package controlclient
  4. import (
  5. "context"
  6. "encoding/json"
  7. "fmt"
  8. "net"
  9. "net/netip"
  10. "reflect"
  11. "slices"
  12. "sort"
  13. "strconv"
  14. "sync"
  15. "tailscale.com/envknob"
  16. "tailscale.com/tailcfg"
  17. "tailscale.com/tstime"
  18. "tailscale.com/types/key"
  19. "tailscale.com/types/logger"
  20. "tailscale.com/types/netmap"
  21. "tailscale.com/types/ptr"
  22. "tailscale.com/types/views"
  23. "tailscale.com/util/clientmetric"
  24. "tailscale.com/util/cmpx"
  25. "tailscale.com/wgengine/filter"
  26. )
  27. // mapSession holds the state over a long-polled "map" request to the
  28. // control plane.
  29. //
  30. // It accepts incremental tailcfg.MapResponse values to
  31. // netMapForResponse and returns fully inflated NetworkMaps, filling
  32. // in the omitted data implicit from prior MapResponse values from
  33. // within the same session (the same long-poll HTTP response to the
  34. // one MapRequest).
  35. type mapSession struct {
  36. // Immutable fields.
  37. nu NetmapUpdater // called on changes (in addition to the optional hooks below)
  38. privateNodeKey key.NodePrivate
  39. publicNodeKey key.NodePublic
  40. logf logger.Logf
  41. vlogf logger.Logf
  42. machinePubKey key.MachinePublic
  43. altClock tstime.Clock // if nil, regular time is used
  44. cancel context.CancelFunc // always non-nil, shuts down caller's base long poll context
  45. watchdogReset chan struct{} // send to request that the long poll activity watchdog timeout be reset
  46. // sessionAliveCtx is a Background-based context that's alive for the
  47. // duration of the mapSession that we own the lifetime of. It's closed by
  48. // sessionAliveCtxClose.
  49. sessionAliveCtx context.Context
  50. sessionAliveCtxClose context.CancelFunc // closes sessionAliveCtx
  51. // Optional hooks, set once before use.
  52. // onDebug specifies what to do with a *tailcfg.Debug message.
  53. // If the watchdogReset chan is nil, it's not used. Otherwise it can be sent to
  54. // to request that the long poll activity watchdog timeout be reset.
  55. onDebug func(_ context.Context, _ *tailcfg.Debug, watchdogReset chan<- struct{}) error
  56. // onConciseNetMapSummary, if non-nil, is called with the Netmap.VeryConcise summary
  57. // whenever a map response is received.
  58. onConciseNetMapSummary func(string)
  59. // onSelfNodeChanged is called before the NetmapUpdater if the self node was
  60. // changed.
  61. onSelfNodeChanged func(*netmap.NetworkMap)
  62. // Fields storing state over the course of multiple MapResponses.
  63. lastNode tailcfg.NodeView
  64. peers map[tailcfg.NodeID]*tailcfg.NodeView // pointer to view (oddly). same pointers as sortedPeers.
  65. sortedPeers []*tailcfg.NodeView // same pointers as peers, but sorted by Node.ID
  66. lastDNSConfig *tailcfg.DNSConfig
  67. lastDERPMap *tailcfg.DERPMap
  68. lastUserProfile map[tailcfg.UserID]tailcfg.UserProfile
  69. lastPacketFilterRules views.Slice[tailcfg.FilterRule]
  70. lastParsedPacketFilter []filter.Match
  71. lastSSHPolicy *tailcfg.SSHPolicy
  72. collectServices bool
  73. lastDomain string
  74. lastDomainAuditLogID string
  75. lastHealth []string
  76. lastPopBrowserURL string
  77. stickyDebug tailcfg.Debug // accumulated opt.Bool values
  78. lastTKAInfo *tailcfg.TKAInfo
  79. lastNetmapSummary string // from NetworkMap.VeryConcise
  80. }
  81. // newMapSession returns a mostly unconfigured new mapSession.
  82. //
  83. // Modify its optional fields on the returned value before use.
  84. //
  85. // It must have its Close method called to release resources.
  86. func newMapSession(privateNodeKey key.NodePrivate, nu NetmapUpdater) *mapSession {
  87. ms := &mapSession{
  88. nu: nu,
  89. privateNodeKey: privateNodeKey,
  90. publicNodeKey: privateNodeKey.Public(),
  91. lastDNSConfig: new(tailcfg.DNSConfig),
  92. lastUserProfile: map[tailcfg.UserID]tailcfg.UserProfile{},
  93. watchdogReset: make(chan struct{}),
  94. // Non-nil no-op defaults, to be optionally overridden by the caller.
  95. logf: logger.Discard,
  96. vlogf: logger.Discard,
  97. cancel: func() {},
  98. onDebug: func(context.Context, *tailcfg.Debug, chan<- struct{}) error { return nil },
  99. onConciseNetMapSummary: func(string) {},
  100. onSelfNodeChanged: func(*netmap.NetworkMap) {},
  101. }
  102. ms.sessionAliveCtx, ms.sessionAliveCtxClose = context.WithCancel(context.Background())
  103. return ms
  104. }
  105. func (ms *mapSession) clock() tstime.Clock {
  106. return cmpx.Or[tstime.Clock](ms.altClock, tstime.StdClock{})
  107. }
  108. // StartWatchdog starts the session's watchdog timer.
  109. // If there's no activity in too long, it tears down the connection.
  110. // Call Close to release these resources.
  111. func (ms *mapSession) StartWatchdog() {
  112. timer, timedOutChan := ms.clock().NewTimer(watchdogTimeout)
  113. go func() {
  114. defer timer.Stop()
  115. for {
  116. select {
  117. case <-ms.sessionAliveCtx.Done():
  118. ms.vlogf("netmap: ending timeout goroutine")
  119. return
  120. case <-timedOutChan:
  121. ms.logf("map response long-poll timed out!")
  122. ms.cancel()
  123. return
  124. case <-ms.watchdogReset:
  125. if !timer.Stop() {
  126. select {
  127. case <-timedOutChan:
  128. case <-ms.sessionAliveCtx.Done():
  129. ms.vlogf("netmap: ending timeout goroutine")
  130. return
  131. }
  132. }
  133. ms.vlogf("netmap: reset timeout timer")
  134. timer.Reset(watchdogTimeout)
  135. }
  136. }
  137. }()
  138. }
  139. func (ms *mapSession) Close() {
  140. ms.sessionAliveCtxClose()
  141. }
  142. // HandleNonKeepAliveMapResponse handles a non-KeepAlive MapResponse (full or
  143. // incremental).
  144. //
  145. // All fields that are valid on a KeepAlive MapResponse have already been
  146. // handled.
  147. //
  148. // TODO(bradfitz): make this handle all fields later. For now (2023-08-20) this
  149. // is [re]factoring progress enough.
  150. func (ms *mapSession) HandleNonKeepAliveMapResponse(ctx context.Context, resp *tailcfg.MapResponse) error {
  151. if debug := resp.Debug; debug != nil {
  152. if err := ms.onDebug(ctx, debug, ms.watchdogReset); err != nil {
  153. return err
  154. }
  155. }
  156. if DevKnob.StripEndpoints() {
  157. for _, p := range resp.Peers {
  158. p.Endpoints = nil
  159. }
  160. for _, p := range resp.PeersChanged {
  161. p.Endpoints = nil
  162. }
  163. }
  164. // For responses that mutate the self node, check for updated nodeAttrs.
  165. if resp.Node != nil {
  166. if DevKnob.StripCaps() {
  167. resp.Node.Capabilities = nil
  168. }
  169. setControlKnobsFromNodeAttrs(resp.Node.Capabilities)
  170. }
  171. // Call Node.InitDisplayNames on any changed nodes.
  172. initDisplayNames(cmpx.Or(resp.Node.View(), ms.lastNode), resp)
  173. ms.patchifyPeersChanged(resp)
  174. ms.updateStateFromResponse(resp)
  175. nm := ms.netmap()
  176. ms.lastNetmapSummary = nm.VeryConcise()
  177. ms.onConciseNetMapSummary(ms.lastNetmapSummary)
  178. // If the self node changed, we might need to update persist.
  179. if resp.Node != nil {
  180. ms.onSelfNodeChanged(nm)
  181. }
  182. ms.nu.UpdateFullNetmap(nm)
  183. return nil
  184. }
  185. // updateStats are some stats from updateStateFromResponse, primarily for
  186. // testing. It's meant to be cheap enough to always compute, though. It doesn't
  187. // allocate.
  188. type updateStats struct {
  189. allNew bool
  190. added int
  191. removed int
  192. changed int
  193. }
  194. // updateStateFromResponse updates ms from res. It takes ownership of res.
  195. func (ms *mapSession) updateStateFromResponse(resp *tailcfg.MapResponse) {
  196. ms.updatePeersStateFromResponse(resp)
  197. if resp.Node != nil {
  198. ms.lastNode = resp.Node.View()
  199. }
  200. for _, up := range resp.UserProfiles {
  201. ms.lastUserProfile[up.ID] = up
  202. }
  203. // TODO(bradfitz): clean up old user profiles? maybe not worth it.
  204. if dm := resp.DERPMap; dm != nil {
  205. ms.vlogf("netmap: new map contains DERP map")
  206. // Zero-valued fields in a DERPMap mean that we're not changing
  207. // anything and are using the previous value(s).
  208. if ldm := ms.lastDERPMap; ldm != nil {
  209. if dm.Regions == nil {
  210. dm.Regions = ldm.Regions
  211. dm.OmitDefaultRegions = ldm.OmitDefaultRegions
  212. }
  213. if dm.HomeParams == nil {
  214. dm.HomeParams = ldm.HomeParams
  215. } else if oldhh := ldm.HomeParams; oldhh != nil {
  216. // Propagate sub-fields of HomeParams
  217. hh := dm.HomeParams
  218. if hh.RegionScore == nil {
  219. hh.RegionScore = oldhh.RegionScore
  220. }
  221. }
  222. }
  223. ms.lastDERPMap = dm
  224. }
  225. if pf := resp.PacketFilter; pf != nil {
  226. var err error
  227. ms.lastPacketFilterRules = views.SliceOf(pf)
  228. ms.lastParsedPacketFilter, err = filter.MatchesFromFilterRules(pf)
  229. if err != nil {
  230. ms.logf("parsePacketFilter: %v", err)
  231. }
  232. }
  233. if c := resp.DNSConfig; c != nil {
  234. ms.lastDNSConfig = c
  235. }
  236. if p := resp.SSHPolicy; p != nil {
  237. ms.lastSSHPolicy = p
  238. }
  239. if v, ok := resp.CollectServices.Get(); ok {
  240. ms.collectServices = v
  241. }
  242. if resp.Domain != "" {
  243. ms.lastDomain = resp.Domain
  244. }
  245. if resp.DomainDataPlaneAuditLogID != "" {
  246. ms.lastDomainAuditLogID = resp.DomainDataPlaneAuditLogID
  247. }
  248. if resp.Health != nil {
  249. ms.lastHealth = resp.Health
  250. }
  251. if resp.TKAInfo != nil {
  252. ms.lastTKAInfo = resp.TKAInfo
  253. }
  254. }
  255. var (
  256. patchDERPRegion = clientmetric.NewCounter("controlclient_patch_derp")
  257. patchEndpoints = clientmetric.NewCounter("controlclient_patch_endpoints")
  258. patchCap = clientmetric.NewCounter("controlclient_patch_capver")
  259. patchKey = clientmetric.NewCounter("controlclient_patch_key")
  260. patchDiscoKey = clientmetric.NewCounter("controlclient_patch_discokey")
  261. patchOnline = clientmetric.NewCounter("controlclient_patch_online")
  262. patchLastSeen = clientmetric.NewCounter("controlclient_patch_lastseen")
  263. patchKeyExpiry = clientmetric.NewCounter("controlclient_patch_keyexpiry")
  264. patchCapabilities = clientmetric.NewCounter("controlclient_patch_capabilities")
  265. patchKeySignature = clientmetric.NewCounter("controlclient_patch_keysig")
  266. patchifiedPeer = clientmetric.NewCounter("controlclient_patchified_peer")
  267. patchifiedPeerEqual = clientmetric.NewCounter("controlclient_patchified_peer_equal")
  268. )
  269. // updatePeersStateFromResponseres updates ms.peers and ms.sortedPeers from res. It takes ownership of res.
  270. func (ms *mapSession) updatePeersStateFromResponse(resp *tailcfg.MapResponse) (stats updateStats) {
  271. defer func() {
  272. if stats.removed > 0 || stats.added > 0 {
  273. ms.rebuildSorted()
  274. }
  275. }()
  276. if ms.peers == nil {
  277. ms.peers = make(map[tailcfg.NodeID]*tailcfg.NodeView)
  278. }
  279. if len(resp.Peers) > 0 {
  280. // Not delta encoded.
  281. stats.allNew = true
  282. keep := make(map[tailcfg.NodeID]bool, len(resp.Peers))
  283. for _, n := range resp.Peers {
  284. keep[n.ID] = true
  285. if vp, ok := ms.peers[n.ID]; ok {
  286. stats.changed++
  287. *vp = n.View()
  288. } else {
  289. stats.added++
  290. ms.peers[n.ID] = ptr.To(n.View())
  291. }
  292. }
  293. for id := range ms.peers {
  294. if !keep[id] {
  295. stats.removed++
  296. delete(ms.peers, id)
  297. }
  298. }
  299. // Peers precludes all other delta operations so just return.
  300. return
  301. }
  302. for _, id := range resp.PeersRemoved {
  303. if _, ok := ms.peers[id]; ok {
  304. delete(ms.peers, id)
  305. stats.removed++
  306. }
  307. }
  308. for _, n := range resp.PeersChanged {
  309. if vp, ok := ms.peers[n.ID]; ok {
  310. stats.changed++
  311. *vp = n.View()
  312. } else {
  313. stats.added++
  314. ms.peers[n.ID] = ptr.To(n.View())
  315. }
  316. }
  317. for nodeID, seen := range resp.PeerSeenChange {
  318. if vp, ok := ms.peers[nodeID]; ok {
  319. mut := vp.AsStruct()
  320. if seen {
  321. mut.LastSeen = ptr.To(clock.Now())
  322. } else {
  323. mut.LastSeen = nil
  324. }
  325. *vp = mut.View()
  326. stats.changed++
  327. }
  328. }
  329. for nodeID, online := range resp.OnlineChange {
  330. if vp, ok := ms.peers[nodeID]; ok {
  331. mut := vp.AsStruct()
  332. mut.Online = ptr.To(online)
  333. *vp = mut.View()
  334. stats.changed++
  335. }
  336. }
  337. for _, pc := range resp.PeersChangedPatch {
  338. vp, ok := ms.peers[pc.NodeID]
  339. if !ok {
  340. continue
  341. }
  342. stats.changed++
  343. mut := vp.AsStruct()
  344. if pc.DERPRegion != 0 {
  345. mut.DERP = fmt.Sprintf("%s:%v", tailcfg.DerpMagicIP, pc.DERPRegion)
  346. patchDERPRegion.Add(1)
  347. }
  348. if pc.Cap != 0 {
  349. mut.Cap = pc.Cap
  350. patchCap.Add(1)
  351. }
  352. if pc.Endpoints != nil {
  353. mut.Endpoints = pc.Endpoints
  354. patchEndpoints.Add(1)
  355. }
  356. if pc.Key != nil {
  357. mut.Key = *pc.Key
  358. patchKey.Add(1)
  359. }
  360. if pc.DiscoKey != nil {
  361. mut.DiscoKey = *pc.DiscoKey
  362. patchDiscoKey.Add(1)
  363. }
  364. if v := pc.Online; v != nil {
  365. mut.Online = ptr.To(*v)
  366. patchOnline.Add(1)
  367. }
  368. if v := pc.LastSeen; v != nil {
  369. mut.LastSeen = ptr.To(*v)
  370. patchLastSeen.Add(1)
  371. }
  372. if v := pc.KeyExpiry; v != nil {
  373. mut.KeyExpiry = *v
  374. patchKeyExpiry.Add(1)
  375. }
  376. if v := pc.Capabilities; v != nil {
  377. mut.Capabilities = *v
  378. patchCapabilities.Add(1)
  379. }
  380. if v := pc.KeySignature; v != nil {
  381. mut.KeySignature = v
  382. patchKeySignature.Add(1)
  383. }
  384. *vp = mut.View()
  385. }
  386. return
  387. }
  388. // rebuildSorted rebuilds ms.sortedPeers from ms.peers. It should be called
  389. // after any additions or removals from peers.
  390. func (ms *mapSession) rebuildSorted() {
  391. if ms.sortedPeers == nil {
  392. ms.sortedPeers = make([]*tailcfg.NodeView, 0, len(ms.peers))
  393. } else {
  394. if len(ms.sortedPeers) > len(ms.peers) {
  395. clear(ms.sortedPeers[len(ms.peers):])
  396. }
  397. ms.sortedPeers = ms.sortedPeers[:0]
  398. }
  399. for _, p := range ms.peers {
  400. ms.sortedPeers = append(ms.sortedPeers, p)
  401. }
  402. sort.Slice(ms.sortedPeers, func(i, j int) bool {
  403. return ms.sortedPeers[i].ID() < ms.sortedPeers[j].ID()
  404. })
  405. }
  406. func (ms *mapSession) addUserProfile(nm *netmap.NetworkMap, userID tailcfg.UserID) {
  407. if userID == 0 {
  408. return
  409. }
  410. if _, dup := nm.UserProfiles[userID]; dup {
  411. // Already populated it from a previous peer.
  412. return
  413. }
  414. if up, ok := ms.lastUserProfile[userID]; ok {
  415. nm.UserProfiles[userID] = up
  416. }
  417. }
  418. var debugPatchifyPeer = envknob.RegisterBool("TS_DEBUG_PATCHIFY_PEER")
  419. // patchifyPeersChanged mutates resp to promote PeersChanged entries to PeersChangedPatch
  420. // when possible.
  421. func (ms *mapSession) patchifyPeersChanged(resp *tailcfg.MapResponse) {
  422. filtered := resp.PeersChanged[:0]
  423. for _, n := range resp.PeersChanged {
  424. if p, ok := ms.patchifyPeer(n); ok {
  425. patchifiedPeer.Add(1)
  426. if debugPatchifyPeer() {
  427. patchj, _ := json.Marshal(p)
  428. ms.logf("debug: patchifyPeer[ID=%v]: %s", n.ID, patchj)
  429. }
  430. if p != nil {
  431. resp.PeersChangedPatch = append(resp.PeersChangedPatch, p)
  432. } else {
  433. patchifiedPeerEqual.Add(1)
  434. }
  435. } else {
  436. filtered = append(filtered, n)
  437. }
  438. }
  439. resp.PeersChanged = filtered
  440. if len(resp.PeersChanged) == 0 {
  441. resp.PeersChanged = nil
  442. }
  443. }
  444. var nodeFields = sync.OnceValue(getNodeFields)
  445. // getNodeFields returns the fails of tailcfg.Node.
  446. func getNodeFields() []string {
  447. rt := reflect.TypeOf((*tailcfg.Node)(nil)).Elem()
  448. ret := make([]string, rt.NumField())
  449. for i := 0; i < rt.NumField(); i++ {
  450. ret[i] = rt.Field(i).Name
  451. }
  452. return ret
  453. }
  454. // patchifyPeer returns a *tailcfg.PeerChange of the session's existing copy of
  455. // the n.ID Node to n.
  456. //
  457. // It returns ok=false if a patch can't be made, (V, ok) on a delta, or (nil,
  458. // true) if all the fields were identical (a zero change).
  459. func (ms *mapSession) patchifyPeer(n *tailcfg.Node) (_ *tailcfg.PeerChange, ok bool) {
  460. was, ok := ms.peers[n.ID]
  461. if !ok {
  462. return nil, false
  463. }
  464. return peerChangeDiff(*was, n)
  465. }
  466. // peerChangeDiff returns the difference from 'was' to 'n', if possible.
  467. //
  468. // It returns (nil, true) if the fields were identical.
  469. func peerChangeDiff(was tailcfg.NodeView, n *tailcfg.Node) (_ *tailcfg.PeerChange, ok bool) {
  470. var ret *tailcfg.PeerChange
  471. pc := func() *tailcfg.PeerChange {
  472. if ret == nil {
  473. ret = new(tailcfg.PeerChange)
  474. }
  475. return ret
  476. }
  477. for _, field := range nodeFields() {
  478. switch field {
  479. default:
  480. // The whole point of using reflect in this function is to panic
  481. // here in tests if we forget to handle a new field.
  482. panic("unhandled field: " + field)
  483. case "computedHostIfDifferent", "ComputedName", "ComputedNameWithHost":
  484. // Caller's responsibility to have populated these.
  485. continue
  486. case "DataPlaneAuditLogID":
  487. // Not sent for peers.
  488. case "ID":
  489. if was.ID() != n.ID {
  490. return nil, false
  491. }
  492. case "StableID":
  493. if was.StableID() != n.StableID {
  494. return nil, false
  495. }
  496. case "Name":
  497. if was.Name() != n.Name {
  498. return nil, false
  499. }
  500. case "User":
  501. if was.User() != n.User {
  502. return nil, false
  503. }
  504. case "Sharer":
  505. if was.Sharer() != n.Sharer {
  506. return nil, false
  507. }
  508. case "Key":
  509. if was.Key() != n.Key {
  510. pc().Key = ptr.To(n.Key)
  511. }
  512. case "KeyExpiry":
  513. if !was.KeyExpiry().Equal(n.KeyExpiry) {
  514. pc().KeyExpiry = ptr.To(n.KeyExpiry)
  515. }
  516. case "KeySignature":
  517. if !was.KeySignature().Equal(n.KeySignature) {
  518. pc().KeySignature = slices.Clone(n.KeySignature)
  519. }
  520. case "Machine":
  521. if was.Machine() != n.Machine {
  522. return nil, false
  523. }
  524. case "DiscoKey":
  525. if was.DiscoKey() != n.DiscoKey {
  526. pc().DiscoKey = ptr.To(n.DiscoKey)
  527. }
  528. case "Addresses":
  529. if !views.SliceEqual(was.Addresses(), views.SliceOf(n.Addresses)) {
  530. return nil, false
  531. }
  532. case "AllowedIPs":
  533. if !views.SliceEqual(was.AllowedIPs(), views.SliceOf(n.AllowedIPs)) {
  534. return nil, false
  535. }
  536. case "Endpoints":
  537. if !views.SliceEqual(was.Endpoints(), views.SliceOf(n.Endpoints)) {
  538. pc().Endpoints = slices.Clone(n.Endpoints)
  539. }
  540. case "DERP":
  541. if was.DERP() != n.DERP {
  542. ip, portStr, err := net.SplitHostPort(n.DERP)
  543. if err != nil || ip != "127.3.3.40" {
  544. return nil, false
  545. }
  546. port, err := strconv.Atoi(portStr)
  547. if err != nil || port < 1 || port > 65535 {
  548. return nil, false
  549. }
  550. pc().DERPRegion = port
  551. }
  552. case "Hostinfo":
  553. if !was.Hostinfo().Valid() && !n.Hostinfo.Valid() {
  554. continue
  555. }
  556. if !was.Hostinfo().Valid() || !n.Hostinfo.Valid() {
  557. return nil, false
  558. }
  559. if !was.Hostinfo().Equal(n.Hostinfo) {
  560. return nil, false
  561. }
  562. case "Created":
  563. if !was.Created().Equal(n.Created) {
  564. return nil, false
  565. }
  566. case "Cap":
  567. if was.Cap() != n.Cap {
  568. pc().Cap = n.Cap
  569. }
  570. case "Tags":
  571. if !views.SliceEqual(was.Tags(), views.SliceOf(n.Tags)) {
  572. return nil, false
  573. }
  574. case "PrimaryRoutes":
  575. if !views.SliceEqual(was.PrimaryRoutes(), views.SliceOf(n.PrimaryRoutes)) {
  576. return nil, false
  577. }
  578. case "Online":
  579. wasOnline := was.Online()
  580. if n.Online != nil && wasOnline != nil && *n.Online != *wasOnline {
  581. pc().Online = ptr.To(*n.Online)
  582. }
  583. case "LastSeen":
  584. wasSeen := was.LastSeen()
  585. if n.LastSeen != nil && wasSeen != nil && !wasSeen.Equal(*n.LastSeen) {
  586. pc().LastSeen = ptr.To(*n.LastSeen)
  587. }
  588. case "MachineAuthorized":
  589. if was.MachineAuthorized() != n.MachineAuthorized {
  590. return nil, false
  591. }
  592. case "Capabilities":
  593. if !views.SliceEqual(was.Capabilities(), views.SliceOf(n.Capabilities)) {
  594. pc().Capabilities = ptr.To(n.Capabilities)
  595. }
  596. case "UnsignedPeerAPIOnly":
  597. if was.UnsignedPeerAPIOnly() != n.UnsignedPeerAPIOnly {
  598. return nil, false
  599. }
  600. case "IsWireGuardOnly":
  601. if was.IsWireGuardOnly() != n.IsWireGuardOnly {
  602. return nil, false
  603. }
  604. case "Expired":
  605. if was.Expired() != n.Expired {
  606. return nil, false
  607. }
  608. case "SelfNodeV4MasqAddrForThisPeer":
  609. va, vb := was.SelfNodeV4MasqAddrForThisPeer(), n.SelfNodeV4MasqAddrForThisPeer
  610. if va == nil && vb == nil {
  611. continue
  612. }
  613. if va == nil || vb == nil || *va != *vb {
  614. return nil, false
  615. }
  616. }
  617. }
  618. if ret != nil {
  619. ret.NodeID = n.ID
  620. }
  621. return ret, true
  622. }
  623. // netmap returns a fully populated NetworkMap from the last state seen from
  624. // a call to updateStateFromResponse, filling in omitted
  625. // information from prior MapResponse values.
  626. func (ms *mapSession) netmap() *netmap.NetworkMap {
  627. peerViews := make([]tailcfg.NodeView, len(ms.sortedPeers))
  628. for i, vp := range ms.sortedPeers {
  629. peerViews[i] = *vp
  630. }
  631. nm := &netmap.NetworkMap{
  632. NodeKey: ms.publicNodeKey,
  633. PrivateKey: ms.privateNodeKey,
  634. MachineKey: ms.machinePubKey,
  635. Peers: peerViews,
  636. UserProfiles: make(map[tailcfg.UserID]tailcfg.UserProfile),
  637. Domain: ms.lastDomain,
  638. DomainAuditLogID: ms.lastDomainAuditLogID,
  639. DNS: *ms.lastDNSConfig,
  640. PacketFilter: ms.lastParsedPacketFilter,
  641. PacketFilterRules: ms.lastPacketFilterRules,
  642. SSHPolicy: ms.lastSSHPolicy,
  643. CollectServices: ms.collectServices,
  644. DERPMap: ms.lastDERPMap,
  645. ControlHealth: ms.lastHealth,
  646. TKAEnabled: ms.lastTKAInfo != nil && !ms.lastTKAInfo.Disabled,
  647. }
  648. if ms.lastTKAInfo != nil && ms.lastTKAInfo.Head != "" {
  649. if err := nm.TKAHead.UnmarshalText([]byte(ms.lastTKAInfo.Head)); err != nil {
  650. ms.logf("error unmarshalling TKAHead: %v", err)
  651. nm.TKAEnabled = false
  652. }
  653. }
  654. if node := ms.lastNode; node.Valid() {
  655. nm.SelfNode = node
  656. nm.Expiry = node.KeyExpiry()
  657. nm.Name = node.Name()
  658. nm.Addresses = filterSelfAddresses(node.Addresses().AsSlice())
  659. if node.MachineAuthorized() {
  660. nm.MachineStatus = tailcfg.MachineAuthorized
  661. } else {
  662. nm.MachineStatus = tailcfg.MachineUnauthorized
  663. }
  664. }
  665. ms.addUserProfile(nm, nm.User())
  666. for _, peer := range peerViews {
  667. ms.addUserProfile(nm, peer.Sharer())
  668. ms.addUserProfile(nm, peer.User())
  669. }
  670. if DevKnob.ForceProxyDNS() {
  671. nm.DNS.Proxied = true
  672. }
  673. return nm
  674. }
  675. func nodesSorted(v []*tailcfg.Node) bool {
  676. for i, n := range v {
  677. if i > 0 && n.ID <= v[i-1].ID {
  678. return false
  679. }
  680. }
  681. return true
  682. }
  683. func sortNodes(v []*tailcfg.Node) {
  684. sort.Slice(v, func(i, j int) bool { return v[i].ID < v[j].ID })
  685. }
  686. func cloneNodes(v1 []*tailcfg.Node) []*tailcfg.Node {
  687. if v1 == nil {
  688. return nil
  689. }
  690. v2 := make([]*tailcfg.Node, len(v1))
  691. for i, n := range v1 {
  692. v2[i] = n.Clone()
  693. }
  694. return v2
  695. }
  696. var debugSelfIPv6Only = envknob.RegisterBool("TS_DEBUG_SELF_V6_ONLY")
  697. func filterSelfAddresses(in []netip.Prefix) (ret []netip.Prefix) {
  698. switch {
  699. default:
  700. return in
  701. case debugSelfIPv6Only():
  702. for _, a := range in {
  703. if a.Addr().Is6() {
  704. ret = append(ret, a)
  705. }
  706. }
  707. return ret
  708. }
  709. }