package mesh import ( "net" "net/netip" "net/url" "sort" "strings" "time" ) const ( PeerConnectionIntentMaintain = "maintain" PeerConnectionIntentProbe = "probe" PeerConnectionIntentRecover = "recover" ) const ( PeerTransportModeDirect = "direct" PeerTransportModePrivateLAN = "private_lan" PeerTransportModeCorporateLAN = "corporate_lan" PeerTransportModeOutboundOnly = "outbound_only" PeerTransportModeRelayRequired = "relay_required" PeerTransportModeRelayControl = "relay_control" PeerTransportModeUnknown = "unknown" ) type PeerConnectionIntentPlanConfig struct { PeerCache PeerCacheSnapshot RecoveryPlan PeerRecoveryPlan RendezvousLeases []PeerRendezvousLease PreferredRegion string Now time.Time } type PeerConnectionIntentPlan struct { Mode string `json:"mode"` IntentCount int `json:"intent_count"` MaintainCount int `json:"maintain_count"` ProbeCount int `json:"probe_count"` RecoverCount int `json:"recover_count"` DirectCount int `json:"direct_count"` PrivateLANCount int `json:"private_lan_count"` CorporateLANCount int `json:"corporate_lan_count"` OutboundOnlyCount int `json:"outbound_only_count"` RelayRequiredCount int `json:"relay_required_count"` RelayControlCount int `json:"relay_control_count"` RendezvousRequiredCount int `json:"rendezvous_required_count"` RendezvousResolvedCount int `json:"rendezvous_resolved_count"` RendezvousLeaseCount int `json:"rendezvous_lease_count"` GeneratedAt time.Time `json:"generated_at"` Intents []PeerConnectionIntent `json:"intents,omitempty"` } type PeerConnectionIntent struct { NodeID string `json:"node_id"` Action string `json:"action"` Reason string `json:"reason"` Endpoint string `json:"endpoint,omitempty"` ConnectionState string `json:"connection_state"` Transport string `json:"transport,omitempty"` TransportMode string `json:"transport_mode"` Reachability string `json:"reachability,omitempty"` ConnectivityMode string `json:"connectivity_mode,omitempty"` NATType string `json:"nat_type,omitempty"` Region string `json:"region,omitempty"` PolicyTags []string `json:"policy_tags,omitempty"` RequiresRendezvous bool `json:"requires_rendezvous"` RendezvousResolved bool `json:"rendezvous_resolved"` DirectCandidate bool `json:"direct_candidate"` RelayCandidate bool `json:"relay_candidate"` BestCandidateID string `json:"best_candidate_id,omitempty"` BestPeerCertSHA256 string `json:"best_peer_cert_sha256,omitempty"` RendezvousLeaseID string `json:"rendezvous_lease_id,omitempty"` RelayNodeID string `json:"relay_node_id,omitempty"` RelayEndpoint string `json:"relay_endpoint,omitempty"` ControlPlaneOnly bool `json:"control_plane_only"` RecoverySeed bool `json:"recovery_seed"` Priority int `json:"priority"` GeneratedAt time.Time `json:"generated_at"` } func PlanPeerConnectionIntents(cfg PeerConnectionIntentPlanConfig) PeerConnectionIntentPlan { now := normalizedNow(cfg.Now) entryByNode := map[string]PeerCacheEntry{} for _, entry := range cfg.PeerCache.Entries { if strings.TrimSpace(entry.NodeID) == "" { continue } entryByNode[entry.NodeID] = entry } intents := make([]PeerConnectionIntent, 0, len(cfg.RecoveryPlan.Candidates)) for _, candidate := range cfg.RecoveryPlan.Candidates { if strings.TrimSpace(candidate.NodeID) == "" { continue } entry := entryByNode[candidate.NodeID] intent := PeerConnectionIntent{ NodeID: candidate.NodeID, Action: connectionIntentAction(candidate), Reason: candidate.Reason, Endpoint: candidate.Endpoint, ConnectionState: candidate.ConnectionState, Transport: firstNonEmpty(candidate.BestTransport, entry.BestTransport), Reachability: entry.BestReachability, ConnectivityMode: entry.BestConnectivity, NATType: entry.BestNATType, Region: entry.BestRegion, PolicyTags: append([]string{}, entry.BestPolicyTags...), BestCandidateID: firstNonEmpty(candidate.BestCandidateID, entry.BestCandidateID), BestPeerCertSHA256: entry.BestPeerCertSHA256, RendezvousLeaseID: entry.RendezvousLeaseID, RelayNodeID: entry.RelayNodeID, RelayEndpoint: entry.RelayEndpoint, RelayCandidate: entry.RelayControl, ControlPlaneOnly: entry.RelayControl, RecoverySeed: candidate.RecoverySeed || entry.RecoverySeed, Priority: candidate.Priority, GeneratedAt: now, } mode, requiresRendezvous, directCandidate := classifyPeerTransport(intent, cfg.PreferredRegion) intent.TransportMode = mode intent.RequiresRendezvous = requiresRendezvous intent.DirectCandidate = directCandidate if intent.RequiresRendezvous { if lease, ok := rendezvousLeaseForPeer(cfg.RendezvousLeases, intent.NodeID, now); ok { applyRendezvousLease(&intent, lease, cfg.PeerCache.LocalNodeID) } } intents = append(intents, intent) } sort.SliceStable(intents, func(i, j int) bool { if intents[i].Priority != intents[j].Priority { return intents[i].Priority > intents[j].Priority } return intents[i].NodeID < intents[j].NodeID }) plan := PeerConnectionIntentPlan{ Mode: cfg.RecoveryPlan.Mode, IntentCount: len(intents), GeneratedAt: now, Intents: intents, } for _, intent := range intents { switch intent.Action { case PeerConnectionIntentMaintain: plan.MaintainCount++ case PeerConnectionIntentProbe: plan.ProbeCount++ case PeerConnectionIntentRecover: plan.RecoverCount++ } switch intent.TransportMode { case PeerTransportModeDirect: plan.DirectCount++ case PeerTransportModePrivateLAN: plan.PrivateLANCount++ case PeerTransportModeCorporateLAN: plan.CorporateLANCount++ case PeerTransportModeOutboundOnly: plan.OutboundOnlyCount++ case PeerTransportModeRelayRequired: plan.RelayRequiredCount++ case PeerTransportModeRelayControl: plan.RelayControlCount++ } if intent.RequiresRendezvous { plan.RendezvousRequiredCount++ } if intent.RendezvousResolved { plan.RendezvousResolvedCount++ } if intent.RendezvousLeaseID != "" { plan.RendezvousLeaseCount++ } } return plan } func connectionIntentAction(candidate PeerRecoveryCandidate) string { switch candidate.Reason { case "maintain_ready": return PeerConnectionIntentMaintain case "recover_degraded", "recover_seed", "recover_warm", "recover_peer": return PeerConnectionIntentRecover default: return PeerConnectionIntentProbe } } func classifyPeerTransport(intent PeerConnectionIntent, preferredRegion string) (string, bool, bool) { transport := strings.ToLower(strings.TrimSpace(intent.Transport)) connectivity := strings.ToLower(strings.TrimSpace(intent.ConnectivityMode)) reachability := strings.ToLower(strings.TrimSpace(intent.Reachability)) region := strings.TrimSpace(intent.Region) preferredRegion = strings.TrimSpace(preferredRegion) tags := lowerStringSet(intent.PolicyTags) if strings.Contains(transport, "relay") || connectivity == "relay_required" || reachability == "relay" { return PeerTransportModeRelayRequired, true, false } if connectivity == "outbound_only" || reachability == "outbound_only" { return PeerTransportModeOutboundOnly, true, false } if tags["corp-lan"] || tags["same-site"] { return PeerTransportModeCorporateLAN, false, true } if tags["private-lan"] || reachability == "private" || endpointHasPrivateHost(intent.Endpoint) { if preferredRegion != "" && region != "" && !strings.EqualFold(region, preferredRegion) { return PeerTransportModeRelayRequired, true, false } return PeerTransportModePrivateLAN, false, true } if strings.Contains(transport, "direct") || reachability == "public" || connectivity == "direct" { return PeerTransportModeDirect, false, true } return PeerTransportModeUnknown, false, false } func rendezvousLeaseForPeer(leases []PeerRendezvousLease, peerNodeID string, now time.Time) (PeerRendezvousLease, bool) { now = normalizedNow(now) candidates := make([]PeerRendezvousLease, 0, len(leases)) for _, lease := range leases { if strings.TrimSpace(lease.PeerNodeID) != peerNodeID || strings.TrimSpace(lease.RelayEndpoint) == "" || strings.TrimSpace(lease.RelayNodeID) == "" || !lease.ControlPlaneOnly || lease.ExpiresAt.IsZero() || !lease.ExpiresAt.After(now) { continue } candidates = append(candidates, lease) } if len(candidates) == 0 { return PeerRendezvousLease{}, false } sort.SliceStable(candidates, func(i, j int) bool { leftPriority := candidates[i].Priority rightPriority := candidates[j].Priority if leftPriority <= 0 { leftPriority = 100 } if rightPriority <= 0 { rightPriority = 100 } if leftPriority != rightPriority { return leftPriority < rightPriority } if !candidates[i].ExpiresAt.Equal(candidates[j].ExpiresAt) { return candidates[i].ExpiresAt.After(candidates[j].ExpiresAt) } return candidates[i].LeaseID < candidates[j].LeaseID }) return candidates[0], true } func applyRendezvousLease(intent *PeerConnectionIntent, lease PeerRendezvousLease, localNodeID string) { localRelay := strings.TrimSpace(lease.RelayNodeID) == strings.TrimSpace(localNodeID) if !localRelay { intent.Endpoint = strings.TrimRight(strings.TrimSpace(lease.RelayEndpoint), "/") } if localRelay { intent.Transport = "reverse_quic" } else { intent.Transport = firstNonEmpty(lease.Transport, "relay_quic") } intent.TransportMode = PeerTransportModeRelayControl intent.RequiresRendezvous = false intent.RendezvousResolved = true intent.DirectCandidate = false intent.RelayCandidate = true intent.RendezvousLeaseID = lease.LeaseID intent.RelayNodeID = lease.RelayNodeID intent.RelayEndpoint = strings.TrimRight(strings.TrimSpace(lease.RelayEndpoint), "/") intent.ControlPlaneOnly = true if certSHA256 := rendezvousLeasePeerCertSHA256(lease); certSHA256 != "" && !localRelay { intent.BestPeerCertSHA256 = certSHA256 } if lease.ConnectivityMode != "" { intent.ConnectivityMode = lease.ConnectivityMode } } func endpointHasPrivateHost(rawEndpoint string) bool { addr, ok := endpointHostAddr(rawEndpoint) if !ok { return false } return addr.IsPrivate() || addr.IsLoopback() || addr.IsLinkLocalUnicast() } func endpointHasUnspecifiedHost(rawEndpoint string) bool { addr, ok := endpointHostAddr(rawEndpoint) return ok && addr.IsUnspecified() } func endpointHostAddr(rawEndpoint string) (netip.Addr, bool) { rawEndpoint = strings.TrimSpace(rawEndpoint) if rawEndpoint == "" { return netip.Addr{}, false } host := rawEndpoint if parsed, err := url.Parse(rawEndpoint); err == nil && parsed.Host != "" { host = parsed.Host } if splitHost, _, err := net.SplitHostPort(host); err == nil { host = splitHost } addr, err := netip.ParseAddr(strings.Trim(host, "[]")) if err != nil { return netip.Addr{}, false } return addr, true } func lowerStringSet(values []string) map[string]bool { out := map[string]bool{} for _, value := range values { value = strings.ToLower(strings.TrimSpace(value)) if value != "" { out[value] = true } } return out } func firstNonEmpty(values ...string) string { for _, value := range values { if strings.TrimSpace(value) != "" { return strings.TrimSpace(value) } } return "" }