diff --git a/management/proto/management.pb.go b/management/proto/management.pb.go index b6b88e2da..d9cad58e3 100644 --- a/management/proto/management.pb.go +++ b/management/proto/management.pb.go @@ -1358,12 +1358,13 @@ type Route struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` - Prefix string `protobuf:"bytes,2,opt,name=Prefix,proto3" json:"Prefix,omitempty"` - PrefixType int64 `protobuf:"varint,3,opt,name=PrefixType,proto3" json:"PrefixType,omitempty"` - Peer string `protobuf:"bytes,4,opt,name=Peer,proto3" json:"Peer,omitempty"` - Metric int64 `protobuf:"varint,5,opt,name=Metric,proto3" json:"Metric,omitempty"` - Masquerade bool `protobuf:"varint,6,opt,name=Masquerade,proto3" json:"Masquerade,omitempty"` + ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` + Network string `protobuf:"bytes,2,opt,name=Network,proto3" json:"Network,omitempty"` + NetworkType int64 `protobuf:"varint,3,opt,name=NetworkType,proto3" json:"NetworkType,omitempty"` + Peer string `protobuf:"bytes,4,opt,name=Peer,proto3" json:"Peer,omitempty"` + Metric int64 `protobuf:"varint,5,opt,name=Metric,proto3" json:"Metric,omitempty"` + Masquerade bool `protobuf:"varint,6,opt,name=Masquerade,proto3" json:"Masquerade,omitempty"` + NetID string `protobuf:"bytes,7,opt,name=NetID,proto3" json:"NetID,omitempty"` } func (x *Route) Reset() { @@ -1405,16 +1406,16 @@ func (x *Route) GetID() string { return "" } -func (x *Route) GetPrefix() string { +func (x *Route) GetNetwork() string { if x != nil { - return x.Prefix + return x.Network } return "" } -func (x *Route) GetPrefixType() int64 { +func (x *Route) GetNetworkType() int64 { if x != nil { - return x.PrefixType + return x.NetworkType } return 0 } @@ -1440,6 +1441,13 @@ func (x *Route) GetMasquerade() bool { return false } +func (x *Route) GetNetID() string { + if x != nil { + return x.NetID + } + return "" +} + var File_management_proto protoreflect.FileDescriptor var file_management_proto_rawDesc = []byte{ @@ -1607,42 +1615,43 @@ var file_management_proto_rawDesc = []byte{ 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x41, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x41, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x9b, 0x01, 0x0a, 0x05, 0x52, 0x6f, + 0x08, 0x41, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x22, 0xb5, 0x01, 0x0a, 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x1e, 0x0a, 0x0a, 0x50, - 0x72, 0x65, 0x66, 0x69, 0x78, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0a, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x50, - 0x65, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x50, 0x65, 0x65, 0x72, 0x12, - 0x16, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x06, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x1e, 0x0a, 0x0a, 0x4d, 0x61, 0x73, 0x71, 0x75, - 0x65, 0x72, 0x61, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x4d, 0x61, 0x73, - 0x71, 0x75, 0x65, 0x72, 0x61, 0x64, 0x65, 0x32, 0xf7, 0x02, 0x0a, 0x11, 0x4d, 0x61, 0x6e, 0x61, - 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x45, 0x0a, - 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, + 0x02, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x20, 0x0a, + 0x0b, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0b, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x50, 0x65, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x50, + 0x65, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x06, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x1e, 0x0a, 0x0a, 0x4d, + 0x61, 0x73, 0x71, 0x75, 0x65, 0x72, 0x61, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0a, 0x4d, 0x61, 0x73, 0x71, 0x75, 0x65, 0x72, 0x61, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x4e, + 0x65, 0x74, 0x49, 0x44, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4e, 0x65, 0x74, 0x49, + 0x44, 0x32, 0xf7, 0x02, 0x0a, 0x11, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x45, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, + 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, + 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x46, + 0x0a, 0x04, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x04, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x1c, 0x2e, 0x6d, - 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, - 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, - 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, - 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x42, 0x0a, 0x0c, - 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x11, 0x2e, 0x6d, - 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, - 0x1d, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x33, 0x0a, 0x09, 0x69, 0x73, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x12, 0x11, 0x2e, - 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, - 0x6c, 0x6f, 0x77, 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, - 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, - 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x67, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x42, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x11, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1d, 0x2e, 0x6d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x33, 0x0a, 0x09, 0x69, 0x73, + 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x12, 0x11, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, + 0x5a, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x1c, 0x2e, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x6d, 0x61, + 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/management/proto/management.proto b/management/proto/management.proto index 010c1c2ef..e67dd7488 100644 --- a/management/proto/management.proto +++ b/management/proto/management.proto @@ -235,9 +235,10 @@ message ProviderConfig { // Route represents a route.Route object message Route { string ID = 1; - string Prefix = 2; - int64 PrefixType = 3; + string Network = 2; + int64 NetworkType = 3; string Peer = 4; int64 Metric = 5; bool Masquerade = 6; + string NetID = 7; } \ No newline at end of file diff --git a/management/server/account.go b/management/server/account.go index 5a727a9b1..5ad3b3729 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -70,7 +70,7 @@ type AccountManager interface { DeleteRule(accountId, ruleID string) error ListRules(accountId string) ([]*Rule, error) GetRoute(accountID, routeID string) (*route.Route, error) - CreateRoute(accountID string, prefix, peer, description string, masquerade bool, metric int, enabled bool) (*route.Route, error) + CreateRoute(accountID string, prefix, peer, description, netID string, masquerade bool, metric int, enabled bool) (*route.Route, error) SaveRoute(accountID string, route *route.Route) error UpdateRoute(accountID string, routeID string, operations []RouteUpdateOperation) (*route.Route, error) DeleteRoute(accountID, routeID string) error diff --git a/management/server/file_store.go b/management/server/file_store.go index 4d4101e44..13ab90f1b 100644 --- a/management/server/file_store.go +++ b/management/server/file_store.go @@ -134,11 +134,11 @@ func restore(file string) (*FileStore, error) { if store.AccountPrefix2RouteIDs[account.Id] == nil { store.AccountPrefix2RouteIDs[account.Id] = make(map[string][]string) } - if _, ok := store.AccountPrefix2RouteIDs[account.Id][route.Prefix.String()]; !ok { - store.AccountPrefix2RouteIDs[account.Id][route.Prefix.String()] = make([]string, 0) + if _, ok := store.AccountPrefix2RouteIDs[account.Id][route.Network.String()]; !ok { + store.AccountPrefix2RouteIDs[account.Id][route.Network.String()] = make([]string, 0) } - store.AccountPrefix2RouteIDs[account.Id][route.Prefix.String()] = append( - store.AccountPrefix2RouteIDs[account.Id][route.Prefix.String()], + store.AccountPrefix2RouteIDs[account.Id][route.Network.String()] = append( + store.AccountPrefix2RouteIDs[account.Id][route.Network.String()], route.ID, ) } @@ -340,11 +340,11 @@ func (s *FileStore) SaveAccount(account *Account) error { if s.AccountPrefix2RouteIDs[account.Id] == nil { s.AccountPrefix2RouteIDs[account.Id] = make(map[string][]string) } - if _, ok := s.AccountPrefix2RouteIDs[account.Id][route.Prefix.String()]; !ok { - s.AccountPrefix2RouteIDs[account.Id][route.Prefix.String()] = make([]string, 0) + if _, ok := s.AccountPrefix2RouteIDs[account.Id][route.Network.String()]; !ok { + s.AccountPrefix2RouteIDs[account.Id][route.Network.String()] = make([]string, 0) } - s.AccountPrefix2RouteIDs[account.Id][route.Prefix.String()] = append( - s.AccountPrefix2RouteIDs[account.Id][route.Prefix.String()], + s.AccountPrefix2RouteIDs[account.Id][route.Network.String()] = append( + s.AccountPrefix2RouteIDs[account.Id][route.Network.String()], route.ID, ) } diff --git a/management/server/http/api/openapi.yml b/management/server/http/api/openapi.yml index aa6159c20..51367c0a8 100644 --- a/management/server/http/api/openapi.yml +++ b/management/server/http/api/openapi.yml @@ -282,14 +282,19 @@ components: description: description: Route description type: string + network_id: + description: Route network identifier, to group HA routes + type: string + maxLength: 40 + minLength: 1 enabled: description: Route status type: boolean peer: description: Peer Identifier associated with route type: string - prefix: - description: Prefix or network range in CIDR format + network: + description: Network range in CIDR format type: string metric: description: Route metric number. Lowest number has higher priority @@ -302,9 +307,10 @@ components: required: - id - description + - network_id - enabled - peer - - prefix + - network - metric - masquerade Route: @@ -314,12 +320,12 @@ components: id: description: Route Id type: string - prefix_type: - description: Prefix type indicating if it is IPv4 or IPv6 + network_type: + description: Network type indicating if it is IPv4 or IPv6 type: string required: - id - - prefix_type + - network_type - $ref: '#/components/schemas/RouteRequest' RoutePatchOperation: allOf: @@ -329,7 +335,7 @@ components: path: description: Route field to update in form / type: string - enum: [ "prefix","description","enabled","peer","metric","masquerade" ] + enum: [ "network","network_id","description","enabled","peer","metric","masquerade" ] required: - path diff --git a/management/server/http/api/types.gen.go b/management/server/http/api/types.gen.go index e175ce9fe..2817a6d21 100644 --- a/management/server/http/api/types.gen.go +++ b/management/server/http/api/types.gen.go @@ -44,8 +44,9 @@ const ( RoutePatchOperationPathEnabled RoutePatchOperationPath = "enabled" RoutePatchOperationPathMasquerade RoutePatchOperationPath = "masquerade" RoutePatchOperationPathMetric RoutePatchOperationPath = "metric" + RoutePatchOperationPathNetwork RoutePatchOperationPath = "network" + RoutePatchOperationPathNetworkId RoutePatchOperationPath = "network_id" RoutePatchOperationPathPeer RoutePatchOperationPath = "peer" - RoutePatchOperationPathPrefix RoutePatchOperationPath = "prefix" ) // Defines values for RulePatchOperationOp. @@ -184,14 +185,17 @@ type Route struct { // Route metric number. Lowest number has higher priority Metric int `json:"metric"` + // Network range in CIDR format + Network string `json:"network"` + + // Route network identifier, to group HA routes + NetworkId string `json:"network_id"` + + // Network type indicating if it is IPv4 or IPv6 + NetworkType string `json:"network_type"` + // Peer Identifier associated with route Peer string `json:"peer"` - - // Prefix or network range in CIDR format - Prefix string `json:"prefix"` - - // Prefix type indicating if it is IPv4 or IPv6 - PrefixType string `json:"prefix_type"` } // RoutePatchOperation defines model for RoutePatchOperation. @@ -226,11 +230,14 @@ type RouteRequest struct { // Route metric number. Lowest number has higher priority Metric int `json:"metric"` + // Network range in CIDR format + Network string `json:"network"` + + // Route network identifier, to group HA routes + NetworkId string `json:"network_id"` + // Peer Identifier associated with route Peer string `json:"peer"` - - // Prefix or network range in CIDR format - Prefix string `json:"prefix"` } // Rule defines model for Rule. diff --git a/management/server/http/routes.go b/management/server/http/routes.go index b9a945bec..eb817c01e 100644 --- a/management/server/http/routes.go +++ b/management/server/http/routes.go @@ -12,6 +12,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "net/http" + "unicode/utf8" ) // Routes is the routes handler of the account @@ -78,13 +79,18 @@ func (h *Routes) CreateRouteHandler(w http.ResponseWriter, r *http.Request) { peerKey = peer.Key } - _, newPrefix, err := route.ParsePrefix(req.Prefix) + _, newPrefix, err := route.ParseNetwork(req.Network) if err != nil { - http.Error(w, fmt.Sprintf("couldn't parse update prefix %s", req.Prefix), http.StatusBadRequest) + http.Error(w, fmt.Sprintf("couldn't parse update prefix %s", req.Network), http.StatusBadRequest) return } - newRoute, err := h.accountManager.CreateRoute(account.Id, newPrefix.String(), peerKey, req.Description, req.Masquerade, req.Metric, req.Enabled) + if utf8.RuneCountInString(req.NetworkId) > route.MaxNetIDChar || req.NetworkId == "" { + http.Error(w, fmt.Sprintf("identifier should be between 1 and %d", route.MaxNetIDChar), http.StatusBadRequest) + return + } + + newRoute, err := h.accountManager.CreateRoute(account.Id, newPrefix.String(), peerKey, req.Description, req.NetworkId, req.Masquerade, req.Metric, req.Enabled) if err != nil { log.Error(err) http.Redirect(w, r, "/", http.StatusInternalServerError) @@ -123,9 +129,9 @@ func (h *Routes) UpdateRouteHandler(w http.ResponseWriter, r *http.Request) { return } - prefixType, newPrefix, err := route.ParsePrefix(req.Prefix) + prefixType, newPrefix, err := route.ParseNetwork(req.Network) if err != nil { - http.Error(w, fmt.Sprintf("couldn't parse update prefix %s for route ID %s", req.Prefix, routeID), http.StatusBadRequest) + http.Error(w, fmt.Sprintf("couldn't parse update prefix %s for route ID %s", req.Network, routeID), http.StatusBadRequest) return } @@ -140,10 +146,16 @@ func (h *Routes) UpdateRouteHandler(w http.ResponseWriter, r *http.Request) { peerKey = peer.Key } + if utf8.RuneCountInString(req.NetworkId) > route.MaxNetIDChar || req.NetworkId == "" { + http.Error(w, fmt.Sprintf("identifier should be between 1 and %d", route.MaxNetIDChar), http.StatusBadRequest) + return + } + newRoute := &route.Route{ ID: routeID, - Prefix: newPrefix, - PrefixType: prefixType, + Network: newPrefix, + NetID: req.NetworkId, + NetworkType: prefixType, Masquerade: req.Masquerade, Peer: peerKey, Metric: req.Metric, @@ -200,14 +212,14 @@ func (h *Routes) PatchRouteHandler(w http.ResponseWriter, r *http.Request) { for _, patch := range req { switch patch.Path { - case api.RoutePatchOperationPathPrefix: + case api.RoutePatchOperationPathNetwork: if patch.Op != api.RoutePatchOperationOpReplace { - http.Error(w, fmt.Sprintf("Prefix field only accepts replace operation, got %s", patch.Op), + http.Error(w, fmt.Sprintf("Network field only accepts replace operation, got %s", patch.Op), http.StatusBadRequest) return } operations = append(operations, server.RouteUpdateOperation{ - Type: server.UpdateRoutePrefix, + Type: server.UpdateRouteNetwork, Values: patch.Value, }) case api.RoutePatchOperationPathDescription: @@ -220,6 +232,16 @@ func (h *Routes) PatchRouteHandler(w http.ResponseWriter, r *http.Request) { Type: server.UpdateRouteDescription, Values: patch.Value, }) + case api.RoutePatchOperationPathNetworkId: + if patch.Op != api.RoutePatchOperationOpReplace { + http.Error(w, fmt.Sprintf("Network Identifier field only accepts replace operation, got %s", patch.Op), + http.StatusBadRequest) + return + } + operations = append(operations, server.RouteUpdateOperation{ + Type: server.UpdateRouteNetworkIdentifier, + Values: patch.Value, + }) case api.RoutePatchOperationPathPeer: if patch.Op != api.RoutePatchOperationOpReplace { http.Error(w, fmt.Sprintf("Peer field only accepts replace operation, got %s", patch.Op), @@ -370,10 +392,11 @@ func toRouteResponse(account *server.Account, serverRoute *route.Route) *api.Rou return &api.Route{ Id: serverRoute.ID, Description: serverRoute.Description, + NetworkId: serverRoute.NetID, Enabled: serverRoute.Enabled, Peer: peerIP, - Prefix: serverRoute.Prefix.String(), - PrefixType: serverRoute.PrefixType.String(), + Network: serverRoute.Network.String(), + NetworkType: serverRoute.NetworkType.String(), Masquerade: serverRoute.Masquerade, Metric: serverRoute.Metric, } diff --git a/management/server/http/routes_test.go b/management/server/http/routes_test.go index f52b7a100..bfca838e5 100644 --- a/management/server/http/routes_test.go +++ b/management/server/http/routes_test.go @@ -34,8 +34,9 @@ const ( var baseExistingRoute = &route.Route{ ID: existingRouteID, Description: "base route", - Prefix: netip.MustParsePrefix("192.168.0.0/24"), - PrefixType: route.IPv4Prefix, + NetID: "awesomeNet", + Network: netip.MustParsePrefix("192.168.0.0/24"), + NetworkType: route.IPv4Network, Metric: 9999, Masquerade: false, Enabled: true, @@ -61,13 +62,14 @@ func initRoutesTestData() *Routes { } return nil, status.Errorf(codes.NotFound, "route with ID %s not found", routeID) }, - CreateRouteFunc: func(accountID string, prefix, peer, description string, masquerade bool, metric int, enabled bool) (*route.Route, error) { - prefixType, p, _ := route.ParsePrefix(prefix) + CreateRouteFunc: func(accountID string, network, peer, description, netID string, masquerade bool, metric int, enabled bool) (*route.Route, error) { + networkType, p, _ := route.ParseNetwork(network) return &route.Route{ ID: existingRouteID, + NetID: netID, Peer: peer, - Prefix: p, - PrefixType: prefixType, + Network: p, + NetworkType: networkType, Description: description, Masquerade: masquerade, Enabled: enabled, @@ -95,10 +97,12 @@ func initRoutesTestData() *Routes { } for _, operation := range operations { switch operation.Type { - case server.UpdateRoutePrefix: - routeToUpdate.PrefixType, routeToUpdate.Prefix, _ = route.ParsePrefix(operation.Values[0]) + case server.UpdateRouteNetwork: + routeToUpdate.NetworkType, routeToUpdate.Network, _ = route.ParseNetwork(operation.Values[0]) case server.UpdateRouteDescription: routeToUpdate.Description = operation.Values[0] + case server.UpdateRouteNetworkIdentifier: + routeToUpdate.NetID = operation.Values[0] case server.UpdateRoutePeer: routeToUpdate.Peer = operation.Values[0] case server.UpdateRouteMetric: @@ -172,15 +176,16 @@ func TestRoutesHandlers(t *testing.T) { requestType: http.MethodPost, requestPath: "/api/routes", requestBody: bytes.NewBuffer( - []byte(fmt.Sprintf("{\"Description\":\"Post\",\"Prefix\":\"192.168.0.0/16\",\"Peer\":\"%s\"}", existingPeerID))), + []byte(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"awesomeNet\",\"Peer\":\"%s\"}", existingPeerID))), expectedStatus: http.StatusOK, expectedBody: true, expectedRoute: &api.Route{ Id: existingRouteID, Description: "Post", - Prefix: "192.168.0.0/16", + NetworkId: "awesomeNet", + Network: "192.168.0.0/16", Peer: existingPeerID, - PrefixType: route.IPv4PrefixString, + NetworkType: route.IPv4NetworkString, Masquerade: false, Enabled: false, }, @@ -189,15 +194,23 @@ func TestRoutesHandlers(t *testing.T) { name: "POST Not Found Peer", requestType: http.MethodPost, requestPath: "/api/routes", - requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Prefix\":\"192.168.0.0/16\",\"Peer\":\"%s\"}", notFoundPeerID)), + requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"awesomeNet\",\"Peer\":\"%s\"}", notFoundPeerID)), expectedStatus: http.StatusUnprocessableEntity, expectedBody: false, }, { - name: "POST Invalid Prefix", + name: "POST Not Invalid Network Identifier", requestType: http.MethodPost, requestPath: "/api/routes", - requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Prefix\":\"192.168.0.0/34\",\"Peer\":\"%s\"}", existingPeerID)), + requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"12345678901234567890qwertyuiopqwertyuiop1\",\"Peer\":\"%s\"}", existingPeerID)), + expectedStatus: http.StatusBadRequest, + expectedBody: false, + }, + { + name: "POST Invalid Network", + requestType: http.MethodPost, + requestPath: "/api/routes", + requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/34\",\"network_id\":\"awesomeNet\",\"Peer\":\"%s\"}", existingPeerID)), expectedStatus: http.StatusBadRequest, expectedBody: false, }, @@ -205,15 +218,16 @@ func TestRoutesHandlers(t *testing.T) { name: "PUT OK", requestType: http.MethodPut, requestPath: "/api/routes/" + existingRouteID, - requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Prefix\":\"192.168.0.0/16\",\"Peer\":\"%s\"}", existingPeerID)), + requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"awesomeNet\",\"Peer\":\"%s\"}", existingPeerID)), expectedStatus: http.StatusOK, expectedBody: true, expectedRoute: &api.Route{ Id: existingRouteID, Description: "Post", - Prefix: "192.168.0.0/16", + NetworkId: "awesomeNet", + Network: "192.168.0.0/16", Peer: existingPeerID, - PrefixType: route.IPv4PrefixString, + NetworkType: route.IPv4NetworkString, Masquerade: false, Enabled: false, }, @@ -222,7 +236,7 @@ func TestRoutesHandlers(t *testing.T) { name: "PUT Not Found Route", requestType: http.MethodPut, requestPath: "/api/routes/" + notFoundRouteID, - requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Prefix\":\"192.168.0.0/16\",\"Peer\":\"%s\"}", existingPeerID)), + requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"awesomeNet\",\"Peer\":\"%s\"}", existingPeerID)), expectedStatus: http.StatusNotFound, expectedBody: false, }, @@ -230,15 +244,23 @@ func TestRoutesHandlers(t *testing.T) { name: "PUT Not Found Peer", requestType: http.MethodPut, requestPath: "/api/routes/" + existingRouteID, - requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Prefix\":\"192.168.0.0/16\",\"Peer\":\"%s\"}", notFoundPeerID)), + requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"awesomeNet\",\"Peer\":\"%s\"}", notFoundPeerID)), expectedStatus: http.StatusUnprocessableEntity, expectedBody: false, }, { - name: "PUT Invalid Prefix", + name: "PUT Invalid Network Identifier", requestType: http.MethodPut, requestPath: "/api/routes/" + existingRouteID, - requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Prefix\":\"192.168.0.0/34\",\"Peer\":\"%s\"}", existingPeerID)), + requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"12345678901234567890qwertyuiopqwertyuiop1\",\"Peer\":\"%s\"}", existingPeerID)), + expectedStatus: http.StatusBadRequest, + expectedBody: false, + }, + { + name: "PUT Invalid Network", + requestType: http.MethodPut, + requestPath: "/api/routes/" + existingRouteID, + requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/34\",\"network_id\":\"awesomeNet\",\"Peer\":\"%s\"}", existingPeerID)), expectedStatus: http.StatusBadRequest, expectedBody: false, }, @@ -252,8 +274,9 @@ func TestRoutesHandlers(t *testing.T) { expectedRoute: &api.Route{ Id: existingRouteID, Description: "NewDesc", - Prefix: baseExistingRoute.Prefix.String(), - PrefixType: route.IPv4PrefixString, + NetworkId: "awesomeNet", + Network: baseExistingRoute.Network.String(), + NetworkType: route.IPv4NetworkString, Masquerade: baseExistingRoute.Masquerade, Enabled: baseExistingRoute.Enabled, Metric: baseExistingRoute.Metric, @@ -269,8 +292,9 @@ func TestRoutesHandlers(t *testing.T) { expectedRoute: &api.Route{ Id: existingRouteID, Description: "NewDesc", - Prefix: baseExistingRoute.Prefix.String(), - PrefixType: route.IPv4PrefixString, + NetworkId: "awesomeNet", + Network: baseExistingRoute.Network.String(), + NetworkType: route.IPv4NetworkString, Peer: existingPeerID, Masquerade: baseExistingRoute.Masquerade, Enabled: baseExistingRoute.Enabled, @@ -289,7 +313,7 @@ func TestRoutesHandlers(t *testing.T) { name: "PATCH Not Found Route", requestType: http.MethodPatch, requestPath: "/api/routes/" + notFoundRouteID, - requestBody: bytes.NewBufferString("[{\"op\":\"replace\",\"path\":\"prefix\",\"value\":[\"192.168.0.0/34\"]}]"), + requestBody: bytes.NewBufferString("[{\"op\":\"replace\",\"path\":\"network\",\"value\":[\"192.168.0.0/34\"]}]"), expectedStatus: http.StatusNotFound, expectedBody: false, }, diff --git a/management/server/mock_server/account_mock.go b/management/server/mock_server/account_mock.go index 6e3118dea..f2698ed1f 100644 --- a/management/server/mock_server/account_mock.go +++ b/management/server/mock_server/account_mock.go @@ -45,7 +45,7 @@ type MockAccountManager struct { UpdatePeerMetaFunc func(peerKey string, meta server.PeerSystemMeta) error UpdatePeerSSHKeyFunc func(peerKey string, sshKey string) error UpdatePeerFunc func(accountID string, peer *server.Peer) (*server.Peer, error) - CreateRouteFunc func(accountID string, prefix, peer, description string, masquerade bool, metric int, enabled bool) (*route.Route, error) + CreateRouteFunc func(accountID string, prefix, peer, description, netID string, masquerade bool, metric int, enabled bool) (*route.Route, error) GetRouteFunc func(accountID, routeID string) (*route.Route, error) SaveRouteFunc func(accountID string, route *route.Route) error UpdateRouteFunc func(accountID string, routeID string, operations []server.RouteUpdateOperation) (*route.Route, error) @@ -369,9 +369,9 @@ func (am *MockAccountManager) UpdatePeer(accountID string, peer *server.Peer) (* } // CreateRoute mock implementation of CreateRoute from server.AccountManager interface -func (am *MockAccountManager) CreateRoute(accountID string, prefix, peer, description string, masquerade bool, metric int, enabled bool) (*route.Route, error) { +func (am *MockAccountManager) CreateRoute(accountID string, network, peer, description, netID string, masquerade bool, metric int, enabled bool) (*route.Route, error) { if am.GetRouteFunc != nil { - return am.CreateRouteFunc(accountID, prefix, peer, description, masquerade, metric, enabled) + return am.CreateRouteFunc(accountID, network, peer, description, netID, masquerade, metric, enabled) } return nil, status.Errorf(codes.Unimplemented, "method CreateRoute is not implemented") } diff --git a/management/server/route.go b/management/server/route.go index f8b4ddffe..0c9fc2e57 100644 --- a/management/server/route.go +++ b/management/server/route.go @@ -9,13 +9,14 @@ import ( "google.golang.org/grpc/status" "net/netip" "strconv" + "unicode/utf8" ) const ( // UpdateRouteDescription indicates a route description update operation UpdateRouteDescription RouteUpdateOperationType = iota - // UpdateRoutePrefix indicates a route IP update operation - UpdateRoutePrefix + // UpdateRouteNetwork indicates a route IP update operation + UpdateRouteNetwork // UpdateRoutePeer indicates a route peer update operation UpdateRoutePeer // UpdateRouteMetric indicates a route metric update operation @@ -24,6 +25,8 @@ const ( UpdateRouteMasquerade // UpdateRouteEnabled indicates a route enabled update operation UpdateRouteEnabled + // UpdateRouteNetworkIdentifier indicates a route net ID update operation + UpdateRouteNetworkIdentifier ) // RouteUpdateOperationType operation type @@ -33,8 +36,8 @@ func (t RouteUpdateOperationType) String() string { switch t { case UpdateRouteDescription: return "UpdateRouteDescription" - case UpdateRoutePrefix: - return "UpdateRoutePrefix" + case UpdateRouteNetwork: + return "UpdateRouteNetwork" case UpdateRoutePeer: return "UpdateRoutePeer" case UpdateRouteMetric: @@ -43,6 +46,8 @@ func (t RouteUpdateOperationType) String() string { return "UpdateRouteMasquerade" case UpdateRouteEnabled: return "UpdateRouteEnabled" + case UpdateRouteNetworkIdentifier: + return "UpdateRouteNetworkIdentifier" default: return "InvalidOperation" } @@ -72,7 +77,7 @@ func (am *DefaultAccountManager) GetRoute(accountID, routeID string) (*route.Rou return nil, status.Errorf(codes.NotFound, "route with ID %s not found", routeID) } -// checkPrefixPeerExists checks the combination of prefix and peer id, if it exists returns an error, otehrwise returns nil +// checkPrefixPeerExists checks the combination of prefix and peer id, if it exists returns an error, otherwise returns nil func (am *DefaultAccountManager) checkPrefixPeerExists(accountID, peer string, prefix netip.Prefix) error { routesWithPrefix, err := am.Store.GetRoutesByPrefix(accountID, prefix) @@ -91,7 +96,7 @@ func (am *DefaultAccountManager) checkPrefixPeerExists(accountID, peer string, p } // CreateRoute creates and saves a new route -func (am *DefaultAccountManager) CreateRoute(accountID string, prefix, peer, description string, masquerade bool, metric int, enabled bool) (*route.Route, error) { +func (am *DefaultAccountManager) CreateRoute(accountID string, network, peer, description, netID string, masquerade bool, metric int, enabled bool) (*route.Route, error) { am.mux.Lock() defer am.mux.Unlock() @@ -101,9 +106,9 @@ func (am *DefaultAccountManager) CreateRoute(accountID string, prefix, peer, des } var newRoute route.Route - prefixType, newPrefix, err := route.ParsePrefix(prefix) + prefixType, newPrefix, err := route.ParseNetwork(network) if err != nil { - return nil, status.Errorf(codes.InvalidArgument, "failed to parse IP %s", prefix) + return nil, status.Errorf(codes.InvalidArgument, "failed to parse IP %s", network) } err = am.checkPrefixPeerExists(accountID, peer, newPrefix) if err != nil { @@ -121,11 +126,16 @@ func (am *DefaultAccountManager) CreateRoute(accountID string, prefix, peer, des return nil, status.Errorf(codes.InvalidArgument, "metric should be between %d and %d", route.MinMetric, route.MaxMetric) } + if utf8.RuneCountInString(netID) > route.MaxNetIDChar || netID == "" { + return nil, status.Errorf(codes.InvalidArgument, "identifier should be between 1 and %d", route.MaxNetIDChar) + } + newRoute.Peer = peer newRoute.ID = xid.New().String() - newRoute.Prefix = newPrefix - newRoute.PrefixType = prefixType + newRoute.Network = newPrefix + newRoute.NetworkType = prefixType newRoute.Description = description + newRoute.NetID = netID newRoute.Masquerade = masquerade newRoute.Metric = metric newRoute.Enabled = enabled @@ -158,14 +168,18 @@ func (am *DefaultAccountManager) SaveRoute(accountID string, routeToSave *route. return status.Errorf(codes.InvalidArgument, "route provided is nil") } - if !routeToSave.Prefix.IsValid() { - return status.Errorf(codes.InvalidArgument, "invalid Prefix %s", routeToSave.Prefix.String()) + if !routeToSave.Network.IsValid() { + return status.Errorf(codes.InvalidArgument, "invalid Prefix %s", routeToSave.Network.String()) } if routeToSave.Metric < route.MinMetric || routeToSave.Metric > route.MaxMetric { return status.Errorf(codes.InvalidArgument, "metric should be between %d and %d", route.MinMetric, route.MaxMetric) } + if utf8.RuneCountInString(routeToSave.NetID) > route.MaxNetIDChar || routeToSave.NetID == "" { + return status.Errorf(codes.InvalidArgument, "identifier should be between 1 and %d", route.MaxNetIDChar) + } + account, err := am.Store.GetAccount(accountID) if err != nil { return status.Errorf(codes.NotFound, "account not found") @@ -214,8 +228,13 @@ func (am *DefaultAccountManager) UpdateRoute(accountID, routeID string, operatio switch operation.Type { case UpdateRouteDescription: newRoute.Description = operation.Values[0] - case UpdateRoutePrefix: - prefixType, prefix, err := route.ParsePrefix(operation.Values[0]) + case UpdateRouteNetworkIdentifier: + if utf8.RuneCountInString(operation.Values[0]) > route.MaxNetIDChar || operation.Values[0] == "" { + return nil, status.Errorf(codes.InvalidArgument, "identifier should be between 1 and %d", route.MaxNetIDChar) + } + newRoute.NetID = operation.Values[0] + case UpdateRouteNetwork: + prefixType, prefix, err := route.ParseNetwork(operation.Values[0]) if err != nil { return nil, status.Errorf(codes.InvalidArgument, "failed to parse IP %s", operation.Values[0]) } @@ -223,8 +242,8 @@ func (am *DefaultAccountManager) UpdateRoute(accountID, routeID string, operatio if err != nil { return nil, err } - newRoute.Prefix = prefix - newRoute.PrefixType = prefixType + newRoute.Network = prefix + newRoute.NetworkType = prefixType case UpdateRoutePeer: if operation.Values[0] != "" { _, peerExist := account.Peers[operation.Values[0]] @@ -233,7 +252,7 @@ func (am *DefaultAccountManager) UpdateRoute(accountID, routeID string, operatio } } - err = am.checkPrefixPeerExists(accountID, operation.Values[0], routeToUpdate.Prefix) + err = am.checkPrefixPeerExists(accountID, operation.Values[0], routeToUpdate.Network) if err != nil { return nil, err } @@ -320,12 +339,13 @@ func (am *DefaultAccountManager) ListRoutes(accountID string) ([]*route.Route, e func toProtocolRoute(route *route.Route) *proto.Route { return &proto.Route{ - ID: route.ID, - Prefix: route.Prefix.String(), - PrefixType: int64(route.PrefixType), - Peer: route.Peer, - Metric: int64(route.Metric), - Masquerade: route.Masquerade, + ID: route.ID, + NetID: route.NetID, + Network: route.Network.String(), + NetworkType: int64(route.NetworkType), + Peer: route.Peer, + Metric: int64(route.Metric), + Masquerade: route.Masquerade, } } diff --git a/management/server/route_test.go b/management/server/route_test.go index 7dbe844db..c11122c80 100644 --- a/management/server/route_test.go +++ b/management/server/route_test.go @@ -14,7 +14,8 @@ const peer2Key = "/yF0+vCfv+mRR5k0dca0TrGdO/oiNeAI58gToZm5NyI=" func TestCreateRoute(t *testing.T) { type input struct { - prefix string + network string + netID string peer string description string masquerade bool @@ -32,7 +33,8 @@ func TestCreateRoute(t *testing.T) { { name: "Happy Path", inputArgs: input{ - prefix: "192.168.0.0/16", + network: "192.168.0.0/16", + netID: "happy", peer: peer1Key, description: "super", masquerade: false, @@ -42,8 +44,9 @@ func TestCreateRoute(t *testing.T) { errFunc: require.NoError, shouldCreate: true, expectedRoute: &route.Route{ - Prefix: netip.MustParsePrefix("192.168.0.0/16"), - PrefixType: route.IPv4Prefix, + Network: netip.MustParsePrefix("192.168.0.0/16"), + NetworkType: route.IPv4Network, + NetID: "happy", Peer: peer1Key, Description: "super", Masquerade: false, @@ -54,7 +57,8 @@ func TestCreateRoute(t *testing.T) { { name: "Bad Prefix", inputArgs: input{ - prefix: "192.168.0.0/34", + network: "192.168.0.0/34", + netID: "happy", peer: peer1Key, description: "super", masquerade: false, @@ -67,7 +71,8 @@ func TestCreateRoute(t *testing.T) { { name: "Bad Peer", inputArgs: input{ - prefix: "192.168.0.0/16", + network: "192.168.0.0/16", + netID: "happy", peer: "notExistingPeer", description: "super", masquerade: false, @@ -80,7 +85,8 @@ func TestCreateRoute(t *testing.T) { { name: "Empty Peer", inputArgs: input{ - prefix: "192.168.0.0/16", + network: "192.168.0.0/16", + netID: "happy", peer: "", description: "super", masquerade: false, @@ -90,8 +96,9 @@ func TestCreateRoute(t *testing.T) { errFunc: require.NoError, shouldCreate: true, expectedRoute: &route.Route{ - Prefix: netip.MustParsePrefix("192.168.0.0/16"), - PrefixType: route.IPv4Prefix, + Network: netip.MustParsePrefix("192.168.0.0/16"), + NetworkType: route.IPv4Network, + NetID: "happy", Peer: "", Description: "super", Masquerade: false, @@ -102,8 +109,9 @@ func TestCreateRoute(t *testing.T) { { name: "Large Metric", inputArgs: input{ - prefix: "192.168.0.0/16", + network: "192.168.0.0/16", peer: peer1Key, + netID: "happy", description: "super", masquerade: false, metric: 99999, @@ -115,7 +123,8 @@ func TestCreateRoute(t *testing.T) { { name: "Small Metric", inputArgs: input{ - prefix: "192.168.0.0/16", + network: "192.168.0.0/16", + netID: "happy", peer: peer1Key, description: "super", masquerade: false, @@ -125,6 +134,34 @@ func TestCreateRoute(t *testing.T) { errFunc: require.Error, shouldCreate: false, }, + { + name: "Large NetID", + inputArgs: input{ + network: "192.168.0.0/16", + peer: peer1Key, + netID: "12345678901234567890qwertyuiopqwertyuiop1", + description: "super", + masquerade: false, + metric: 9999, + enabled: true, + }, + errFunc: require.Error, + shouldCreate: false, + }, + { + name: "Small NetID", + inputArgs: input{ + network: "192.168.0.0/16", + netID: "", + peer: peer1Key, + description: "", + masquerade: false, + metric: 9999, + enabled: true, + }, + errFunc: require.Error, + shouldCreate: false, + }, } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { @@ -140,9 +177,10 @@ func TestCreateRoute(t *testing.T) { outRoute, err := am.CreateRoute( account.Id, - testCase.inputArgs.prefix, + testCase.inputArgs.network, testCase.inputArgs.peer, testCase.inputArgs.description, + testCase.inputArgs.netID, testCase.inputArgs.masquerade, testCase.inputArgs.metric, testCase.inputArgs.enabled, @@ -173,6 +211,8 @@ func TestSaveRoute(t *testing.T) { invalidPrefix, _ := netip.ParsePrefix("192.168.0.0/34") validMetric := 1000 invalidMetric := 99999 + validNetID := "12345678901234567890qw" + invalidNetID := "12345678901234567890qwertyuiopqwertyuiop1" testCases := []struct { name string @@ -189,8 +229,9 @@ func TestSaveRoute(t *testing.T) { name: "Happy Path", existingRoute: &route.Route{ ID: "testingRoute", - Prefix: netip.MustParsePrefix("192.168.0.0/16"), - PrefixType: route.IPv4Prefix, + Network: netip.MustParsePrefix("192.168.0.0/16"), + NetID: validNetID, + NetworkType: route.IPv4Network, Peer: peer1Key, Description: "super", Masquerade: false, @@ -204,8 +245,9 @@ func TestSaveRoute(t *testing.T) { shouldCreate: true, expectedRoute: &route.Route{ ID: "testingRoute", - Prefix: validPrefix, - PrefixType: route.IPv4Prefix, + Network: validPrefix, + NetID: validNetID, + NetworkType: route.IPv4Network, Peer: validPeer, Description: "super", Masquerade: false, @@ -217,8 +259,9 @@ func TestSaveRoute(t *testing.T) { name: "Bad Prefix", existingRoute: &route.Route{ ID: "testingRoute", - Prefix: netip.MustParsePrefix("192.168.0.0/16"), - PrefixType: route.IPv4Prefix, + Network: netip.MustParsePrefix("192.168.0.0/16"), + NetID: validNetID, + NetworkType: route.IPv4Network, Peer: peer1Key, Description: "super", Masquerade: false, @@ -232,8 +275,9 @@ func TestSaveRoute(t *testing.T) { name: "Bad Peer", existingRoute: &route.Route{ ID: "testingRoute", - Prefix: netip.MustParsePrefix("192.168.0.0/16"), - PrefixType: route.IPv4Prefix, + Network: netip.MustParsePrefix("192.168.0.0/16"), + NetID: validNetID, + NetworkType: route.IPv4Network, Peer: peer1Key, Description: "super", Masquerade: false, @@ -247,8 +291,25 @@ func TestSaveRoute(t *testing.T) { name: "Invalid Metric", existingRoute: &route.Route{ ID: "testingRoute", - Prefix: netip.MustParsePrefix("192.168.0.0/16"), - PrefixType: route.IPv4Prefix, + Network: netip.MustParsePrefix("192.168.0.0/16"), + NetID: validNetID, + NetworkType: route.IPv4Network, + Peer: peer1Key, + Description: "super", + Masquerade: false, + Metric: 9999, + Enabled: true, + }, + newMetric: &invalidMetric, + errFunc: require.Error, + }, + { + name: "Invalid NetID", + existingRoute: &route.Route{ + ID: "testingRoute", + Network: netip.MustParsePrefix("192.168.0.0/16"), + NetID: invalidNetID, + NetworkType: route.IPv4Network, Peer: peer1Key, Description: "super", Masquerade: false, @@ -262,8 +323,9 @@ func TestSaveRoute(t *testing.T) { name: "Nil Route", existingRoute: &route.Route{ ID: "testingRoute", - Prefix: netip.MustParsePrefix("192.168.0.0/16"), - PrefixType: route.IPv4Prefix, + Network: netip.MustParsePrefix("192.168.0.0/16"), + NetID: validNetID, + NetworkType: route.IPv4Network, Peer: peer1Key, Description: "super", Masquerade: false, @@ -306,7 +368,7 @@ func TestSaveRoute(t *testing.T) { } if testCase.newPrefix != nil { - routeToSave.Prefix = *testCase.newPrefix + routeToSave.Network = *testCase.newPrefix } } @@ -334,8 +396,9 @@ func TestUpdateRoute(t *testing.T) { existingRoute := &route.Route{ ID: routeID, - Prefix: netip.MustParsePrefix("192.168.0.0/16"), - PrefixType: route.IPv4Prefix, + Network: netip.MustParsePrefix("192.168.0.0/16"), + NetID: "superRoute", + NetworkType: route.IPv4Network, Peer: peer1Key, Description: "super", Masquerade: false, @@ -364,8 +427,9 @@ func TestUpdateRoute(t *testing.T) { shouldCreate: true, expectedRoute: &route.Route{ ID: routeID, - Prefix: netip.MustParsePrefix("192.168.0.0/16"), - PrefixType: route.IPv4Prefix, + Network: netip.MustParsePrefix("192.168.0.0/16"), + NetID: "superRoute", + NetworkType: route.IPv4Network, Peer: peer2Key, Description: "super", Masquerade: false, @@ -382,7 +446,7 @@ func TestUpdateRoute(t *testing.T) { Values: []string{"great"}, }, RouteUpdateOperation{ - Type: UpdateRoutePrefix, + Type: UpdateRouteNetwork, Values: []string{"192.168.0.0/24"}, }, RouteUpdateOperation{ @@ -401,13 +465,18 @@ func TestUpdateRoute(t *testing.T) { Type: UpdateRouteEnabled, Values: []string{"false"}, }, + RouteUpdateOperation{ + Type: UpdateRouteNetworkIdentifier, + Values: []string{"megaRoute"}, + }, }, errFunc: require.NoError, shouldCreate: true, expectedRoute: &route.Route{ ID: routeID, - Prefix: netip.MustParsePrefix("192.168.0.0/24"), - PrefixType: route.IPv4Prefix, + Network: netip.MustParsePrefix("192.168.0.0/24"), + NetID: "megaRoute", + NetworkType: route.IPv4Network, Peer: peer2Key, Description: "great", Masquerade: true, @@ -441,7 +510,7 @@ func TestUpdateRoute(t *testing.T) { existingRoute: existingRoute, operations: []RouteUpdateOperation{ RouteUpdateOperation{ - Type: UpdateRoutePrefix, + Type: UpdateRouteNetwork, Values: []string{"192.168.0.0/34"}, }, }, @@ -471,8 +540,9 @@ func TestUpdateRoute(t *testing.T) { shouldCreate: true, expectedRoute: &route.Route{ ID: routeID, - Prefix: netip.MustParsePrefix("192.168.0.0/16"), - PrefixType: route.IPv4Prefix, + Network: netip.MustParsePrefix("192.168.0.0/16"), + NetID: "superRoute", + NetworkType: route.IPv4Network, Peer: "", Description: "super", Masquerade: false, @@ -480,6 +550,28 @@ func TestUpdateRoute(t *testing.T) { Enabled: true, }, }, + { + name: "Large Network ID", + existingRoute: existingRoute, + operations: []RouteUpdateOperation{ + RouteUpdateOperation{ + Type: UpdateRouteNetworkIdentifier, + Values: []string{"12345678901234567890qwertyuiopqwertyuiop1"}, + }, + }, + errFunc: require.Error, + }, + { + name: "Empty Network ID", + existingRoute: existingRoute, + operations: []RouteUpdateOperation{ + RouteUpdateOperation{ + Type: UpdateRouteNetworkIdentifier, + Values: []string{""}, + }, + }, + errFunc: require.Error, + }, { name: "Invalid Metric", existingRoute: existingRoute, @@ -544,8 +636,8 @@ func TestDeleteRoute(t *testing.T) { testingRoute := &route.Route{ ID: "testingRoute", - Prefix: netip.MustParsePrefix("192.168.0.0/16"), - PrefixType: route.IPv4Prefix, + Network: netip.MustParsePrefix("192.168.0.0/16"), + NetworkType: route.IPv4Network, Peer: peer1Key, Description: "super", Masquerade: false, @@ -592,8 +684,9 @@ func TestGetNetworkMap_RouteSync(t *testing.T) { baseRoute := &route.Route{ ID: "testingRoute", - Prefix: netip.MustParsePrefix("192.168.0.0/16"), - PrefixType: route.IPv4Prefix, + Network: netip.MustParsePrefix("192.168.0.0/16"), + NetID: "superNet", + NetworkType: route.IPv4Network, Peer: peer1Key, Description: "super", Masquerade: false, @@ -615,8 +708,8 @@ func TestGetNetworkMap_RouteSync(t *testing.T) { require.NoError(t, err) require.Len(t, newAccountRoutes.Routes, 0, "new accounts should have no routes") - createdRoute, err := am.CreateRoute(account.Id, baseRoute.Prefix.String(), baseRoute.Peer, - baseRoute.Description, baseRoute.Masquerade, baseRoute.Metric, false) + createdRoute, err := am.CreateRoute(account.Id, baseRoute.Network.String(), baseRoute.Peer, + baseRoute.Description, baseRoute.NetID, baseRoute.Masquerade, baseRoute.Metric, false) require.NoError(t, err) noDisabledRoutes, err := am.GetNetworkMap(peer1Key) diff --git a/route/route.go b/route/route.go index e3ffdb77e..6214a6464 100644 --- a/route/route.go +++ b/route/route.go @@ -14,59 +14,63 @@ const ( MinMetric = 1 // MaxMetric max metric input MaxMetric = 9999 -) -const ( - // InvalidPrefixString invalid prefix type string - InvalidPrefixString = "Invalid" - // IPv4PrefixString IPv4 prefix type string - IPv4PrefixString = "IPv4" - // IPv6PrefixString IPv6 prefix type string - IPv6PrefixString = "IPv6" + // MaxNetIDChar Max Network Identifier + MaxNetIDChar = 40 ) const ( - // InvalidPrefix invalid prefix type - InvalidPrefix PrefixType = iota - // IPv4Prefix IPv4 prefix type - IPv4Prefix - // IPv6Prefix IPv6 prefix type - IPv6Prefix + // InvalidNetworkString invalid network type string + InvalidNetworkString = "Invalid" + // IPv4NetworkString IPv4 network type string + IPv4NetworkString = "IPv4" + // IPv6NetworkString IPv6 network type string + IPv6NetworkString = "IPv6" ) -// PrefixType route prefix type -type PrefixType int +const ( + // InvalidNetwork invalid network type + InvalidNetwork NetworkType = iota + // IPv4Network IPv4 network type + IPv4Network + // IPv6Network IPv6 network type + IPv6Network +) + +// NetworkType route network type +type NetworkType int // String returns prefix type string -func (p PrefixType) String() string { +func (p NetworkType) String() string { switch p { - case IPv4Prefix: - return IPv4PrefixString - case IPv6Prefix: - return IPv6PrefixString + case IPv4Network: + return IPv4NetworkString + case IPv6Network: + return IPv6NetworkString default: - return InvalidPrefixString + return InvalidNetworkString } } // ToPrefixType returns a prefix type -func ToPrefixType(prefix string) PrefixType { +func ToPrefixType(prefix string) NetworkType { switch prefix { - case IPv4PrefixString: - return IPv4Prefix - case IPv6PrefixString: - return IPv6Prefix + case IPv4NetworkString: + return IPv4Network + case IPv6NetworkString: + return IPv6Network default: - return InvalidPrefix + return InvalidNetwork } } // Route represents a route type Route struct { - Prefix netip.Prefix ID string + Network netip.Prefix + NetID string Description string Peer string - PrefixType PrefixType + NetworkType NetworkType Masquerade bool Metric int Enabled bool @@ -77,8 +81,9 @@ func (r *Route) Copy() *Route { return &Route{ ID: r.ID, Description: r.Description, - Prefix: r.Prefix, - PrefixType: r.PrefixType, + NetID: r.NetID, + Network: r.Network, + NetworkType: r.NetworkType, Peer: r.Peer, Metric: r.Metric, Masquerade: r.Masquerade, @@ -90,30 +95,31 @@ func (r *Route) Copy() *Route { func (r *Route) IsEqual(other *Route) bool { return other.ID == r.ID && other.Description == r.Description && - other.Prefix == r.Prefix && - other.PrefixType == r.PrefixType && + other.NetID == r.NetID && + other.Network == r.Network && + other.NetworkType == r.NetworkType && other.Peer == r.Peer && other.Metric == r.Metric && other.Masquerade == r.Masquerade && other.Enabled == r.Enabled } -// ParsePrefix Parses a prefix string and returns a netip.Prefix object and if is invalid, IPv4 or IPv6 -func ParsePrefix(prefixString string) (PrefixType, netip.Prefix, error) { - prefix, err := netip.ParsePrefix(prefixString) +// ParseNetwork Parses a network prefix string and returns a netip.Prefix object and if is invalid, IPv4 or IPv6 +func ParseNetwork(networkString string) (NetworkType, netip.Prefix, error) { + prefix, err := netip.ParsePrefix(networkString) if err != nil { - return InvalidPrefix, netip.Prefix{}, err + return InvalidNetwork, netip.Prefix{}, err } masked := prefix.Masked() if !masked.IsValid() { - return InvalidPrefix, netip.Prefix{}, status.Errorf(codes.InvalidArgument, "invalid range %s", prefixString) + return InvalidNetwork, netip.Prefix{}, status.Errorf(codes.InvalidArgument, "invalid range %s", networkString) } if masked.Addr().Is6() { - return IPv6Prefix, masked, nil + return IPv6Network, masked, nil } - return IPv4Prefix, masked, nil + return IPv4Network, masked, nil }