map.go 23 KB

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