81 lines
2.2 KiB
Go
81 lines
2.2 KiB
Go
package mesh
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
func ValidateProductionEnvelopeRouteConfig(local PeerIdentity, envelope ProductionEnvelope, routes []SyntheticRoute, now time.Time) error {
|
|
if len(routes) == 0 {
|
|
return nil
|
|
}
|
|
route, ok := productionRouteByID(routes, envelope.RouteID)
|
|
if !ok {
|
|
return ErrRouteNotFound
|
|
}
|
|
if route.ClusterID != envelope.ClusterID || route.ClusterID != local.ClusterID {
|
|
return ErrClusterMismatch
|
|
}
|
|
if route.SourceNodeID != envelope.SourceNodeID || route.DestinationNodeID != envelope.DestinationNodeID {
|
|
return ErrInvalidRoutePath
|
|
}
|
|
if route.ExpiresAt.IsZero() || !route.ExpiresAt.After(now.UTC()) || envelope.ExpiresAt.After(route.ExpiresAt) {
|
|
return ErrRouteExpired
|
|
}
|
|
if !contains(route.AllowedChannels, envelope.ChannelClass) {
|
|
return ErrUnauthorizedChannel
|
|
}
|
|
path := routePath(route)
|
|
if len(path) < 2 || path[0] != route.SourceNodeID || path[len(path)-1] != route.DestinationNodeID {
|
|
return ErrInvalidRoutePath
|
|
}
|
|
if len(envelope.RoutePath) > 0 && !sameNodePath(envelope.RoutePath, path) {
|
|
return ErrInvalidRoutePath
|
|
}
|
|
if len(path) > 2 && len(envelope.RoutePath) == 0 {
|
|
return ErrInvalidRoutePath
|
|
}
|
|
currentIndex := indexOf(path, local.NodeID)
|
|
if currentIndex < 0 || envelope.CurrentHopNodeID != local.NodeID {
|
|
return ErrNodeMismatch
|
|
}
|
|
expectedNextHop := local.NodeID
|
|
if local.NodeID != envelope.DestinationNodeID {
|
|
if currentIndex >= len(path)-1 {
|
|
return ErrInvalidRoutePath
|
|
}
|
|
expectedNextHop = path[currentIndex+1]
|
|
}
|
|
if envelope.NextHopNodeID != expectedNextHop {
|
|
return ErrInvalidRoutePath
|
|
}
|
|
if route.MaxTTL > 0 && envelope.TTL > route.MaxTTL {
|
|
return fmt.Errorf("%w: ttl exceeds configured route max_ttl", ErrForwardEnvelopeInvalid)
|
|
}
|
|
if route.MaxHops > 0 && envelope.HopCount > route.MaxHops {
|
|
return fmt.Errorf("%w: hop_count exceeds configured route max_hops", ErrForwardEnvelopeInvalid)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func productionRouteByID(routes []SyntheticRoute, routeID string) (SyntheticRoute, bool) {
|
|
for _, route := range routes {
|
|
if route.RouteID == routeID {
|
|
return route, true
|
|
}
|
|
}
|
|
return SyntheticRoute{}, false
|
|
}
|
|
|
|
func sameNodePath(a []string, b []string) bool {
|
|
if len(a) != len(b) {
|
|
return false
|
|
}
|
|
for i := range a {
|
|
if a[i] != b[i] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|