map.go 23 KB

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