Initial project snapshot
This commit is contained in:
@@ -0,0 +1,303 @@
|
||||
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
|
||||
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"`
|
||||
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"`
|
||||
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,
|
||||
PolicyTags: append([]string{}, entry.BestPolicyTags...),
|
||||
BestCandidateID: firstNonEmpty(candidate.BestCandidateID, entry.BestCandidateID),
|
||||
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)
|
||||
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)
|
||||
}
|
||||
}
|
||||
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) (string, bool, bool) {
|
||||
transport := strings.ToLower(strings.TrimSpace(intent.Transport))
|
||||
connectivity := strings.ToLower(strings.TrimSpace(intent.ConnectivityMode))
|
||||
reachability := strings.ToLower(strings.TrimSpace(intent.Reachability))
|
||||
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) {
|
||||
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) {
|
||||
intent.Endpoint = strings.TrimRight(strings.TrimSpace(lease.RelayEndpoint), "/")
|
||||
intent.Transport = firstNonEmpty(lease.Transport, "relay_control")
|
||||
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 = intent.Endpoint
|
||||
intent.ControlPlaneOnly = true
|
||||
if lease.ConnectivityMode != "" {
|
||||
intent.ConnectivityMode = lease.ConnectivityMode
|
||||
}
|
||||
}
|
||||
|
||||
func endpointHasPrivateHost(rawEndpoint string) bool {
|
||||
rawEndpoint = strings.TrimSpace(rawEndpoint)
|
||||
if rawEndpoint == "" {
|
||||
return 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 false
|
||||
}
|
||||
return addr.IsPrivate() || addr.IsLoopback() || addr.IsLinkLocalUnicast()
|
||||
}
|
||||
|
||||
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 ""
|
||||
}
|
||||
Reference in New Issue
Block a user