2022-08-18 18:22:15 +02:00
|
|
|
package route
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/netip"
|
2023-08-22 17:56:39 +02:00
|
|
|
|
|
|
|
"github.com/netbirdio/netbird/management/server/status"
|
2022-08-18 18:22:15 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// Windows has some limitation regarding metric size that differ from Unix-like systems.
|
|
|
|
// Because of that we are limiting the min and max metric size based on Windows limits:
|
|
|
|
// see based on info from https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/route_ws2008
|
|
|
|
const (
|
|
|
|
// MinMetric max metric input
|
|
|
|
MinMetric = 1
|
|
|
|
// MaxMetric max metric input
|
|
|
|
MaxMetric = 9999
|
2022-08-22 14:10:24 +02:00
|
|
|
// MaxNetIDChar Max Network Identifier
|
|
|
|
MaxNetIDChar = 40
|
2022-08-18 18:22:15 +02:00
|
|
|
)
|
2022-08-22 14:10:24 +02:00
|
|
|
|
2022-08-18 18:22:15 +02:00
|
|
|
const (
|
2022-08-22 14:10:24 +02:00
|
|
|
// InvalidNetworkString invalid network type string
|
|
|
|
InvalidNetworkString = "Invalid"
|
|
|
|
// IPv4NetworkString IPv4 network type string
|
|
|
|
IPv4NetworkString = "IPv4"
|
|
|
|
// IPv6NetworkString IPv6 network type string
|
|
|
|
IPv6NetworkString = "IPv6"
|
2022-08-18 18:22:15 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2022-08-22 14:10:24 +02:00
|
|
|
// InvalidNetwork invalid network type
|
|
|
|
InvalidNetwork NetworkType = iota
|
|
|
|
// IPv4Network IPv4 network type
|
|
|
|
IPv4Network
|
|
|
|
// IPv6Network IPv6 network type
|
|
|
|
IPv6Network
|
2022-08-18 18:22:15 +02:00
|
|
|
)
|
|
|
|
|
2024-05-06 14:47:49 +02:00
|
|
|
type ID string
|
|
|
|
|
|
|
|
type NetID string
|
|
|
|
|
|
|
|
type HAMap map[HAUniqueID][]*Route
|
|
|
|
|
2022-08-22 14:10:24 +02:00
|
|
|
// NetworkType route network type
|
|
|
|
type NetworkType int
|
2022-08-18 18:22:15 +02:00
|
|
|
|
|
|
|
// String returns prefix type string
|
2022-08-22 14:10:24 +02:00
|
|
|
func (p NetworkType) String() string {
|
2022-08-18 18:22:15 +02:00
|
|
|
switch p {
|
2022-08-22 14:10:24 +02:00
|
|
|
case IPv4Network:
|
|
|
|
return IPv4NetworkString
|
|
|
|
case IPv6Network:
|
|
|
|
return IPv6NetworkString
|
2022-08-18 18:22:15 +02:00
|
|
|
default:
|
2022-08-22 14:10:24 +02:00
|
|
|
return InvalidNetworkString
|
2022-08-18 18:22:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ToPrefixType returns a prefix type
|
2022-08-22 14:10:24 +02:00
|
|
|
func ToPrefixType(prefix string) NetworkType {
|
2022-08-18 18:22:15 +02:00
|
|
|
switch prefix {
|
2022-08-22 14:10:24 +02:00
|
|
|
case IPv4NetworkString:
|
|
|
|
return IPv4Network
|
|
|
|
case IPv6NetworkString:
|
|
|
|
return IPv6Network
|
2022-08-18 18:22:15 +02:00
|
|
|
default:
|
2022-08-22 14:10:24 +02:00
|
|
|
return InvalidNetwork
|
2022-08-18 18:22:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Route represents a route
|
|
|
|
type Route struct {
|
2024-05-06 14:47:49 +02:00
|
|
|
ID ID `gorm:"primaryKey"`
|
2023-10-12 15:42:36 +02:00
|
|
|
// AccountID is a reference to Account that this object belongs
|
|
|
|
AccountID string `gorm:"index"`
|
2024-04-18 18:14:21 +02:00
|
|
|
Network netip.Prefix `gorm:"serializer:json"`
|
2024-05-06 14:47:49 +02:00
|
|
|
NetID NetID
|
2022-08-18 18:22:15 +02:00
|
|
|
Description string
|
|
|
|
Peer string
|
2024-04-18 18:14:21 +02:00
|
|
|
PeerGroups []string `gorm:"serializer:json"`
|
2022-08-22 14:10:24 +02:00
|
|
|
NetworkType NetworkType
|
2022-08-18 18:22:15 +02:00
|
|
|
Masquerade bool
|
|
|
|
Metric int
|
|
|
|
Enabled bool
|
2023-10-12 15:42:36 +02:00
|
|
|
Groups []string `gorm:"serializer:json"`
|
2022-08-18 18:22:15 +02:00
|
|
|
}
|
|
|
|
|
2023-01-25 16:29:59 +01:00
|
|
|
// EventMeta returns activity event meta related to the route
|
|
|
|
func (r *Route) EventMeta() map[string]any {
|
2023-09-28 14:32:36 +02:00
|
|
|
return map[string]any{"name": r.NetID, "network_range": r.Network.String(), "peer_id": r.Peer, "peer_groups": r.PeerGroups}
|
2023-01-25 16:29:59 +01:00
|
|
|
}
|
|
|
|
|
2022-08-18 18:22:15 +02:00
|
|
|
// Copy copies a route object
|
|
|
|
func (r *Route) Copy() *Route {
|
2023-08-22 17:56:39 +02:00
|
|
|
route := &Route{
|
2022-08-18 18:22:15 +02:00
|
|
|
ID: r.ID,
|
|
|
|
Description: r.Description,
|
2022-08-22 14:10:24 +02:00
|
|
|
NetID: r.NetID,
|
|
|
|
Network: r.Network,
|
|
|
|
NetworkType: r.NetworkType,
|
2022-08-18 18:22:15 +02:00
|
|
|
Peer: r.Peer,
|
2023-09-28 14:32:36 +02:00
|
|
|
PeerGroups: make([]string, len(r.PeerGroups)),
|
2022-08-18 18:22:15 +02:00
|
|
|
Metric: r.Metric,
|
|
|
|
Masquerade: r.Masquerade,
|
|
|
|
Enabled: r.Enabled,
|
2023-08-22 17:56:39 +02:00
|
|
|
Groups: make([]string, len(r.Groups)),
|
2022-08-18 18:22:15 +02:00
|
|
|
}
|
2023-08-22 17:56:39 +02:00
|
|
|
copy(route.Groups, r.Groups)
|
2023-09-28 14:32:36 +02:00
|
|
|
copy(route.PeerGroups, r.PeerGroups)
|
2023-08-22 17:56:39 +02:00
|
|
|
return route
|
2022-08-18 18:22:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// IsEqual compares one route with the other
|
|
|
|
func (r *Route) IsEqual(other *Route) bool {
|
2024-04-29 18:43:14 +02:00
|
|
|
if r == nil && other == nil {
|
|
|
|
return true
|
|
|
|
} else if r == nil || other == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-08-18 18:22:15 +02:00
|
|
|
return other.ID == r.ID &&
|
|
|
|
other.Description == r.Description &&
|
2022-08-22 14:10:24 +02:00
|
|
|
other.NetID == r.NetID &&
|
|
|
|
other.Network == r.Network &&
|
|
|
|
other.NetworkType == r.NetworkType &&
|
2022-08-18 18:22:15 +02:00
|
|
|
other.Peer == r.Peer &&
|
|
|
|
other.Metric == r.Metric &&
|
|
|
|
other.Masquerade == r.Masquerade &&
|
2022-12-06 10:11:57 +01:00
|
|
|
other.Enabled == r.Enabled &&
|
2023-09-28 14:32:36 +02:00
|
|
|
compareList(r.Groups, other.Groups) &&
|
|
|
|
compareList(r.PeerGroups, other.PeerGroups)
|
2022-08-18 18:22:15 +02:00
|
|
|
}
|
|
|
|
|
2022-08-22 14:10:24 +02:00
|
|
|
// 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)
|
2022-08-18 18:22:15 +02:00
|
|
|
if err != nil {
|
2022-11-11 20:36:45 +01:00
|
|
|
return InvalidNetwork, netip.Prefix{}, status.Errorf(status.InvalidArgument, "invalid network %s", networkString)
|
2022-08-18 18:22:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
masked := prefix.Masked()
|
|
|
|
|
|
|
|
if !masked.IsValid() {
|
2022-11-11 20:36:45 +01:00
|
|
|
return InvalidNetwork, netip.Prefix{}, status.Errorf(status.InvalidArgument, "invalid range %s", networkString)
|
2022-08-18 18:22:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if masked.Addr().Is6() {
|
2022-08-22 14:10:24 +02:00
|
|
|
return IPv6Network, masked, nil
|
2022-08-18 18:22:15 +02:00
|
|
|
}
|
|
|
|
|
2022-08-22 14:10:24 +02:00
|
|
|
return IPv4Network, masked, nil
|
2022-08-18 18:22:15 +02:00
|
|
|
}
|
2022-12-06 10:11:57 +01:00
|
|
|
|
2023-09-28 14:32:36 +02:00
|
|
|
func compareList(list, other []string) bool {
|
2022-12-06 10:11:57 +01:00
|
|
|
if len(list) != len(other) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
for _, id := range list {
|
|
|
|
match := false
|
|
|
|
for _, otherID := range other {
|
|
|
|
if id == otherID {
|
|
|
|
match = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !match {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|