Initial project snapshot
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ScopedSyntheticConfig struct {
|
||||
SchemaVersion string `json:"schema_version"`
|
||||
ClusterID string `json:"cluster_id"`
|
||||
LocalNodeID string `json:"local_node_id"`
|
||||
ConfigVersion string `json:"config_version,omitempty"`
|
||||
PeerDirectoryVersion string `json:"peer_directory_version,omitempty"`
|
||||
PolicyVersion string `json:"policy_version,omitempty"`
|
||||
PeerEndpoints map[string]string `json:"peer_endpoints"`
|
||||
PeerEndpointCandidates map[string][]PeerEndpointCandidate `json:"peer_endpoint_candidates,omitempty"`
|
||||
PeerDirectory []PeerDirectoryEntry `json:"peer_directory,omitempty"`
|
||||
RecoverySeeds []PeerRecoverySeed `json:"recovery_seeds,omitempty"`
|
||||
RendezvousLeases []PeerRendezvousLease `json:"rendezvous_leases,omitempty"`
|
||||
Routes []SyntheticRoute `json:"routes"`
|
||||
}
|
||||
|
||||
type PeerDirectoryEntry struct {
|
||||
NodeID string `json:"node_id"`
|
||||
RouteIDs []string `json:"route_ids,omitempty"`
|
||||
EndpointCount int `json:"endpoint_count"`
|
||||
CandidateCount int `json:"candidate_count"`
|
||||
ConnectivityModes []string `json:"connectivity_modes,omitempty"`
|
||||
RecoverySeed bool `json:"recovery_seed"`
|
||||
}
|
||||
|
||||
type PeerRecoverySeed struct {
|
||||
NodeID string `json:"node_id"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Transport string `json:"transport"`
|
||||
ConnectivityMode string `json:"connectivity_mode,omitempty"`
|
||||
Region string `json:"region,omitempty"`
|
||||
Priority int `json:"priority"`
|
||||
LastVerifiedAt *time.Time `json:"last_verified_at,omitempty"`
|
||||
Metadata json.RawMessage `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type PeerRendezvousLease struct {
|
||||
LeaseID string `json:"lease_id"`
|
||||
PeerNodeID string `json:"peer_node_id"`
|
||||
RelayNodeID string `json:"relay_node_id"`
|
||||
RelayEndpoint string `json:"relay_endpoint"`
|
||||
Transport string `json:"transport"`
|
||||
ConnectivityMode string `json:"connectivity_mode,omitempty"`
|
||||
RouteIDs []string `json:"route_ids,omitempty"`
|
||||
AllowedChannels []string `json:"allowed_channels,omitempty"`
|
||||
Priority int `json:"priority"`
|
||||
ControlPlaneOnly bool `json:"control_plane_only"`
|
||||
IssuedAt time.Time `json:"issued_at"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
Metadata json.RawMessage `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type PeerEndpointCandidate struct {
|
||||
EndpointID string `json:"endpoint_id"`
|
||||
NodeID string `json:"node_id"`
|
||||
Transport string `json:"transport"`
|
||||
Address string `json:"address"`
|
||||
AddressFamily string `json:"address_family,omitempty"`
|
||||
Reachability string `json:"reachability"`
|
||||
NATType string `json:"nat_type,omitempty"`
|
||||
ConnectivityMode string `json:"connectivity_mode"`
|
||||
Region string `json:"region,omitempty"`
|
||||
Priority int `json:"priority"`
|
||||
PolicyTags []string `json:"policy_tags,omitempty"`
|
||||
LastVerifiedAt *time.Time `json:"last_verified_at,omitempty"`
|
||||
Metadata json.RawMessage `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
func LoadScopedSyntheticConfig(path string, local PeerIdentity) (ScopedSyntheticConfig, error) {
|
||||
payload, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return ScopedSyntheticConfig{}, err
|
||||
}
|
||||
var cfg ScopedSyntheticConfig
|
||||
if err := json.Unmarshal(payload, &cfg); err != nil {
|
||||
return ScopedSyntheticConfig{}, fmt.Errorf("parse scoped synthetic mesh config: %w", err)
|
||||
}
|
||||
if err := cfg.Validate(local); err != nil {
|
||||
return ScopedSyntheticConfig{}, err
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (cfg ScopedSyntheticConfig) Validate(local PeerIdentity) error {
|
||||
if cfg.SchemaVersion == "" {
|
||||
return fmt.Errorf("scoped synthetic mesh config schema_version is required")
|
||||
}
|
||||
if cfg.ClusterID == "" || cfg.ClusterID != local.ClusterID {
|
||||
return ErrClusterMismatch
|
||||
}
|
||||
if cfg.LocalNodeID == "" || cfg.LocalNodeID != local.NodeID {
|
||||
return ErrNodeMismatch
|
||||
}
|
||||
for nodeID, endpoint := range cfg.PeerEndpoints {
|
||||
if strings.TrimSpace(nodeID) == "" || strings.TrimSpace(endpoint) == "" {
|
||||
return fmt.Errorf("scoped synthetic mesh config contains empty peer endpoint")
|
||||
}
|
||||
}
|
||||
for nodeID, candidates := range cfg.PeerEndpointCandidates {
|
||||
if strings.TrimSpace(nodeID) == "" {
|
||||
return fmt.Errorf("scoped synthetic mesh config contains empty peer endpoint candidate node")
|
||||
}
|
||||
for _, candidate := range candidates {
|
||||
if strings.TrimSpace(candidate.EndpointID) == "" ||
|
||||
strings.TrimSpace(candidate.NodeID) == "" ||
|
||||
candidate.NodeID != nodeID ||
|
||||
strings.TrimSpace(candidate.Transport) == "" ||
|
||||
strings.TrimSpace(candidate.Address) == "" ||
|
||||
strings.TrimSpace(candidate.Reachability) == "" ||
|
||||
strings.TrimSpace(candidate.ConnectivityMode) == "" {
|
||||
return fmt.Errorf("scoped synthetic mesh config contains invalid peer endpoint candidate")
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := validatePeerDirectory(cfg.PeerDirectory, cfg.LocalNodeID); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateRecoverySeeds(cfg.RecoverySeeds); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateRendezvousLeases(cfg.RendezvousLeases, cfg.Routes, cfg.LocalNodeID); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, route := range cfg.Routes {
|
||||
if route.ClusterID != cfg.ClusterID {
|
||||
return ErrClusterMismatch
|
||||
}
|
||||
path := routePath(route)
|
||||
if len(path) < 2 {
|
||||
return ErrInvalidRoutePath
|
||||
}
|
||||
if !contains(path, cfg.LocalNodeID) {
|
||||
return ErrNodeMismatch
|
||||
}
|
||||
if route.ExpiresAt.IsZero() {
|
||||
return fmt.Errorf("scoped synthetic route %q expires_at is required", route.RouteID)
|
||||
}
|
||||
if !route.ExpiresAt.After(time.Now().UTC()) {
|
||||
return ErrRouteExpired
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validatePeerDirectory(entries []PeerDirectoryEntry, localNodeID string) error {
|
||||
seen := map[string]struct{}{}
|
||||
for _, entry := range entries {
|
||||
nodeID := strings.TrimSpace(entry.NodeID)
|
||||
if nodeID == "" || nodeID == localNodeID {
|
||||
return fmt.Errorf("scoped synthetic mesh config contains invalid peer directory entry")
|
||||
}
|
||||
if _, duplicate := seen[nodeID]; duplicate {
|
||||
return fmt.Errorf("scoped synthetic mesh config contains duplicate peer directory entry")
|
||||
}
|
||||
seen[nodeID] = struct{}{}
|
||||
if entry.EndpointCount < 0 || entry.CandidateCount < 0 {
|
||||
return fmt.Errorf("scoped synthetic mesh config contains invalid peer directory count")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateRecoverySeeds(seeds []PeerRecoverySeed) error {
|
||||
if len(seeds) > 20 {
|
||||
return fmt.Errorf("scoped synthetic mesh config contains too many recovery seeds")
|
||||
}
|
||||
seen := map[string]struct{}{}
|
||||
for _, seed := range seeds {
|
||||
key := strings.TrimSpace(seed.NodeID) + "\x00" + strings.TrimSpace(seed.Endpoint)
|
||||
if strings.TrimSpace(seed.NodeID) == "" ||
|
||||
strings.TrimSpace(seed.Endpoint) == "" ||
|
||||
strings.TrimSpace(seed.Transport) == "" {
|
||||
return fmt.Errorf("scoped synthetic mesh config contains invalid recovery seed")
|
||||
}
|
||||
if _, duplicate := seen[key]; duplicate {
|
||||
return fmt.Errorf("scoped synthetic mesh config contains duplicate recovery seed")
|
||||
}
|
||||
seen[key] = struct{}{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateRendezvousLeases(leases []PeerRendezvousLease, routes []SyntheticRoute, localNodeID string) error {
|
||||
if len(leases) > 20 {
|
||||
return fmt.Errorf("scoped synthetic mesh config contains too many rendezvous leases")
|
||||
}
|
||||
routesByID := map[string]SyntheticRoute{}
|
||||
for _, route := range routes {
|
||||
if strings.TrimSpace(route.RouteID) != "" {
|
||||
routesByID[route.RouteID] = route
|
||||
}
|
||||
}
|
||||
seen := map[string]struct{}{}
|
||||
now := time.Now().UTC()
|
||||
for _, lease := range leases {
|
||||
if strings.TrimSpace(lease.LeaseID) == "" ||
|
||||
strings.TrimSpace(lease.PeerNodeID) == "" ||
|
||||
strings.TrimSpace(lease.RelayNodeID) == "" ||
|
||||
strings.TrimSpace(lease.RelayEndpoint) == "" ||
|
||||
strings.TrimSpace(lease.Transport) == "" ||
|
||||
lease.PeerNodeID == lease.RelayNodeID ||
|
||||
!lease.ControlPlaneOnly ||
|
||||
lease.ExpiresAt.IsZero() ||
|
||||
!lease.ExpiresAt.After(now) ||
|
||||
(len(lease.Metadata) > 0 && !json.Valid(lease.Metadata)) {
|
||||
return fmt.Errorf("scoped synthetic mesh config contains invalid rendezvous lease")
|
||||
}
|
||||
if _, duplicate := seen[lease.LeaseID]; duplicate {
|
||||
return fmt.Errorf("scoped synthetic mesh config contains duplicate rendezvous lease")
|
||||
}
|
||||
seen[lease.LeaseID] = struct{}{}
|
||||
if len(lease.RouteIDs) == 0 {
|
||||
continue
|
||||
}
|
||||
visible := false
|
||||
for _, routeID := range lease.RouteIDs {
|
||||
route, ok := routesByID[routeID]
|
||||
if !ok {
|
||||
return fmt.Errorf("scoped synthetic mesh config contains rendezvous lease for unknown route")
|
||||
}
|
||||
path := routePath(route)
|
||||
if contains(path, localNodeID) && contains(path, lease.PeerNodeID) && contains(path, lease.RelayNodeID) {
|
||||
visible = true
|
||||
}
|
||||
}
|
||||
if !visible {
|
||||
return fmt.Errorf("scoped synthetic mesh config contains out-of-scope rendezvous lease")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user