mirror of
https://github.com/netbirdio/netbird.git
synced 2025-05-30 06:40:15 +02:00
Add routing support to management service (#424)
Management will receive and store routes that are associated with a peer ID. The routes are distributed to peers according to their ACLs.
This commit is contained in:
parent
c39cd2f7b0
commit
4b34a6d6df
8
.github/workflows/golangci-lint.yml
vendored
8
.github/workflows/golangci-lint.yml
vendored
@ -6,12 +6,16 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.18.x
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt update && sudo apt install -y -q libgtk-3-dev libappindicator3-dev libayatana-appindicator3-dev libgl1-mesa-dev xorg-dev
|
run: sudo apt update && sudo apt install -y -q libgtk-3-dev libappindicator3-dev libayatana-appindicator3-dev libgl1-mesa-dev xorg-dev
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v2
|
uses: golangci/golangci-lint-action@v2
|
||||||
with:
|
with:
|
||||||
args: --timeout=6m
|
# SA1019: "io/ioutil" has been deprecated since Go 1.16
|
||||||
|
args: --timeout=6m -e SA1019
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/netbirdio/netbird/client/system"
|
"github.com/netbirdio/netbird/client/system"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
@ -501,7 +500,7 @@ func (s *serviceClient) getSrvConfig() {
|
|||||||
// checkPIDFile exists and return error, or write new.
|
// checkPIDFile exists and return error, or write new.
|
||||||
func checkPIDFile() error {
|
func checkPIDFile() error {
|
||||||
pidFile := path.Join(os.TempDir(), "wiretrustee-ui.pid")
|
pidFile := path.Join(os.TempDir(), "wiretrustee-ui.pid")
|
||||||
if piddata, err := ioutil.ReadFile(pidFile); err == nil {
|
if piddata, err := os.ReadFile(pidFile); err == nil {
|
||||||
if pid, err := strconv.Atoi(string(piddata)); err == nil {
|
if pid, err := strconv.Atoi(string(piddata)); err == nil {
|
||||||
if process, err := os.FindProcess(pid); err == nil {
|
if process, err := os.FindProcess(pid); err == nil {
|
||||||
if err := process.Signal(syscall.Signal(0)); err == nil {
|
if err := process.Signal(syscall.Signal(0)); err == nil {
|
||||||
@ -511,5 +510,5 @@ func checkPIDFile() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ioutil.WriteFile(pidFile, []byte(fmt.Sprintf("%d", os.Getpid())), 0o664)
|
return os.WriteFile(pidFile, []byte(fmt.Sprintf("%d", os.Getpid())), 0o664)
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"golang.org/x/net/http2/h2c"
|
"golang.org/x/net/http2/h2c"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -394,7 +393,7 @@ func copySymLink(source, dest string) error {
|
|||||||
|
|
||||||
func cpDir(src string, dst string) error {
|
func cpDir(src string, dst string) error {
|
||||||
var err error
|
var err error
|
||||||
var fds []os.FileInfo
|
var fds []os.DirEntry
|
||||||
var srcinfo os.FileInfo
|
var srcinfo os.FileInfo
|
||||||
|
|
||||||
if srcinfo, err = os.Stat(src); err != nil {
|
if srcinfo, err = os.Stat(src); err != nil {
|
||||||
@ -405,7 +404,7 @@ func cpDir(src string, dst string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if fds, err = ioutil.ReadDir(src); err != nil {
|
if fds, err = os.ReadDir(src); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, fd := range fds {
|
for _, fd := range fds {
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.26.0
|
// protoc-gen-go v1.26.0
|
||||||
// protoc v3.12.4
|
// protoc v3.21.2
|
||||||
// source: management.proto
|
// source: management.proto
|
||||||
|
|
||||||
package proto
|
package proto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
timestamp "github.com/golang/protobuf/ptypes/timestamp"
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
)
|
)
|
||||||
@ -611,7 +611,7 @@ type ServerKeyResponse struct {
|
|||||||
// Server's Wireguard public key
|
// Server's Wireguard public key
|
||||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||||
// Key expiration timestamp after which the key should be fetched again by the client
|
// Key expiration timestamp after which the key should be fetched again by the client
|
||||||
ExpiresAt *timestamp.Timestamp `protobuf:"bytes,2,opt,name=expiresAt,proto3" json:"expiresAt,omitempty"`
|
ExpiresAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=expiresAt,proto3" json:"expiresAt,omitempty"`
|
||||||
// Version of the Wiretrustee Management Service protocol
|
// Version of the Wiretrustee Management Service protocol
|
||||||
Version int32 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"`
|
Version int32 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"`
|
||||||
}
|
}
|
||||||
@ -655,7 +655,7 @@ func (x *ServerKeyResponse) GetKey() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ServerKeyResponse) GetExpiresAt() *timestamp.Timestamp {
|
func (x *ServerKeyResponse) GetExpiresAt() *timestamppb.Timestamp {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.ExpiresAt
|
return x.ExpiresAt
|
||||||
}
|
}
|
||||||
@ -980,6 +980,8 @@ type NetworkMap struct {
|
|||||||
RemotePeers []*RemotePeerConfig `protobuf:"bytes,3,rep,name=remotePeers,proto3" json:"remotePeers,omitempty"`
|
RemotePeers []*RemotePeerConfig `protobuf:"bytes,3,rep,name=remotePeers,proto3" json:"remotePeers,omitempty"`
|
||||||
// Indicates whether remotePeers array is empty or not to bypass protobuf null and empty array equality.
|
// Indicates whether remotePeers array is empty or not to bypass protobuf null and empty array equality.
|
||||||
RemotePeersIsEmpty bool `protobuf:"varint,4,opt,name=remotePeersIsEmpty,proto3" json:"remotePeersIsEmpty,omitempty"`
|
RemotePeersIsEmpty bool `protobuf:"varint,4,opt,name=remotePeersIsEmpty,proto3" json:"remotePeersIsEmpty,omitempty"`
|
||||||
|
// List of routes to be applied
|
||||||
|
Routes []*Route `protobuf:"bytes,5,rep,name=Routes,proto3" json:"Routes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *NetworkMap) Reset() {
|
func (x *NetworkMap) Reset() {
|
||||||
@ -1042,6 +1044,13 @@ func (x *NetworkMap) GetRemotePeersIsEmpty() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *NetworkMap) GetRoutes() []*Route {
|
||||||
|
if x != nil {
|
||||||
|
return x.Routes
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// RemotePeerConfig represents a configuration of a remote peer.
|
// RemotePeerConfig represents a configuration of a remote peer.
|
||||||
// The properties are used to configure Wireguard Peers sections
|
// The properties are used to configure Wireguard Peers sections
|
||||||
type RemotePeerConfig struct {
|
type RemotePeerConfig struct {
|
||||||
@ -1343,6 +1352,94 @@ func (x *ProviderConfig) GetAudience() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Route represents a route.Route object
|
||||||
|
type Route struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Route) Reset() {
|
||||||
|
*x = Route{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_management_proto_msgTypes[19]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Route) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Route) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Route) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_management_proto_msgTypes[19]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Route.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Route) Descriptor() ([]byte, []int) {
|
||||||
|
return file_management_proto_rawDescGZIP(), []int{19}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Route) GetID() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.ID
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Route) GetPrefix() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Prefix
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Route) GetPrefixType() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.PrefixType
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Route) GetPeer() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Peer
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Route) GetMetric() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Metric
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Route) GetMasquerade() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.Masquerade
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
var File_management_proto protoreflect.FileDescriptor
|
var File_management_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_management_proto_rawDesc = []byte{
|
var file_management_proto_rawDesc = []byte{
|
||||||
@ -1459,7 +1556,7 @@ var file_management_proto_rawDesc = []byte{
|
|||||||
0x0a, 0x09, 0x73, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28,
|
0x0a, 0x09, 0x73, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||||
0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53,
|
0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53,
|
||||||
0x53, 0x48, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x73, 0x73, 0x68, 0x43, 0x6f, 0x6e,
|
0x53, 0x48, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x73, 0x73, 0x68, 0x43, 0x6f, 0x6e,
|
||||||
0x66, 0x69, 0x67, 0x22, 0xcc, 0x01, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4d,
|
0x66, 0x69, 0x67, 0x22, 0xf7, 0x01, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4d,
|
||||||
0x61, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01,
|
0x61, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01,
|
||||||
0x28, 0x04, 0x52, 0x06, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x65,
|
0x28, 0x04, 0x52, 0x06, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x65,
|
||||||
0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16,
|
0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16,
|
||||||
@ -1472,67 +1569,80 @@ var file_management_proto_rawDesc = []byte{
|
|||||||
0x72, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72,
|
0x72, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72,
|
||||||
0x73, 0x49, 0x73, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12,
|
0x73, 0x49, 0x73, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12,
|
||||||
0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x73, 0x49, 0x73, 0x45, 0x6d, 0x70,
|
0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x73, 0x49, 0x73, 0x45, 0x6d, 0x70,
|
||||||
0x74, 0x79, 0x22, 0x83, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65,
|
0x74, 0x79, 0x12, 0x29, 0x0a, 0x06, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03,
|
||||||
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x67, 0x50, 0x75, 0x62,
|
0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e,
|
||||||
0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x67, 0x50, 0x75, 0x62,
|
0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x06, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x22, 0x83, 0x01,
|
||||||
0x4b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x49, 0x70,
|
0x0a, 0x10, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66,
|
||||||
0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64,
|
0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x67, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x01,
|
||||||
0x49, 0x70, 0x73, 0x12, 0x33, 0x0a, 0x09, 0x73, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x67, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x1e,
|
||||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d,
|
0x0a, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x49, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03,
|
||||||
0x65, 0x6e, 0x74, 0x2e, 0x53, 0x53, 0x48, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x73,
|
0x28, 0x09, 0x52, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x49, 0x70, 0x73, 0x12, 0x33,
|
||||||
0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x49, 0x0a, 0x09, 0x53, 0x53, 0x48, 0x43,
|
0x0a, 0x09, 0x73, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x73, 0x68, 0x45, 0x6e, 0x61, 0x62,
|
0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53,
|
||||||
0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, 0x73, 0x68, 0x45, 0x6e,
|
0x53, 0x48, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x73, 0x73, 0x68, 0x43, 0x6f, 0x6e,
|
||||||
0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x73, 0x68, 0x50, 0x75, 0x62, 0x4b,
|
0x66, 0x69, 0x67, 0x22, 0x49, 0x0a, 0x09, 0x53, 0x53, 0x48, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x73, 0x68, 0x50, 0x75, 0x62,
|
0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x73, 0x68, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01,
|
||||||
0x4b, 0x65, 0x79, 0x22, 0x20, 0x0a, 0x1e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x75, 0x74,
|
0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, 0x73, 0x68, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,
|
||||||
0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65,
|
0x12, 0x1c, 0x0a, 0x09, 0x73, 0x73, 0x68, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20,
|
||||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xbf, 0x01, 0x0a, 0x17, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
|
0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x73, 0x68, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x20,
|
||||||
0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6c, 0x6f,
|
0x0a, 0x1e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a,
|
||||||
0x77, 0x12, 0x48, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20,
|
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
0x22, 0xbf, 0x01, 0x0a, 0x17, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f,
|
||||||
0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61,
|
0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x48, 0x0a, 0x08,
|
||||||
0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6c, 0x6f, 0x77, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
|
0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c,
|
||||||
0x72, 0x52, 0x08, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x42, 0x0a, 0x0e, 0x50,
|
0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x65, 0x76, 0x69,
|
||||||
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20,
|
0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46,
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
0x6c, 0x6f, 0x77, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x08, 0x50, 0x72,
|
||||||
0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,
|
0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x42, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64,
|
||||||
0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22,
|
0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
|
||||||
0x16, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x0a, 0x0a, 0x06, 0x48,
|
0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x76,
|
||||||
0x4f, 0x53, 0x54, 0x45, 0x44, 0x10, 0x00, 0x22, 0x84, 0x01, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x76,
|
0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x50, 0x72, 0x6f, 0x76,
|
||||||
0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x6c,
|
0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x16, 0x0a, 0x08, 0x70, 0x72,
|
||||||
0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x43, 0x6c,
|
0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x0a, 0x0a, 0x06, 0x48, 0x4f, 0x53, 0x54, 0x45, 0x44,
|
||||||
0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x22, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74,
|
0x10, 0x00, 0x22, 0x84, 0x01, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43,
|
||||||
0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x43, 0x6c,
|
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49,
|
||||||
0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x44, 0x6f,
|
0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49,
|
||||||
0x6d, 0x61, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x44, 0x6f, 0x6d, 0x61,
|
0x44, 0x12, 0x22, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65,
|
||||||
0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x41, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04,
|
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x41, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x32, 0xf7,
|
0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18,
|
||||||
0x02, 0x0a, 0x11, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72,
|
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x1a, 0x0a,
|
||||||
0x76, 0x69, 0x63, 0x65, 0x12, 0x45, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x1c, 0x2e,
|
0x08, 0x41, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79,
|
0x08, 0x41, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x9b, 0x01, 0x0a, 0x05, 0x52, 0x6f,
|
||||||
0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1c, 0x2e, 0x6d, 0x61,
|
0x75, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74,
|
0x02, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20,
|
||||||
0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x04, 0x53,
|
0x01, 0x28, 0x09, 0x52, 0x06, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x1e, 0x0a, 0x0a, 0x50,
|
||||||
0x79, 0x6e, 0x63, 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
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,
|
||||||
|
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,
|
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,
|
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,
|
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,
|
0x00, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||||
0x4b, 0x65, 0x79, 0x12, 0x11, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
0x74, 0x6f, 0x33,
|
||||||
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 (
|
var (
|
||||||
@ -1548,7 +1658,7 @@ func file_management_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_management_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
var file_management_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||||
var file_management_proto_msgTypes = make([]protoimpl.MessageInfo, 19)
|
var file_management_proto_msgTypes = make([]protoimpl.MessageInfo, 20)
|
||||||
var file_management_proto_goTypes = []interface{}{
|
var file_management_proto_goTypes = []interface{}{
|
||||||
(HostConfig_Protocol)(0), // 0: management.HostConfig.Protocol
|
(HostConfig_Protocol)(0), // 0: management.HostConfig.Protocol
|
||||||
(DeviceAuthorizationFlowProvider)(0), // 1: management.DeviceAuthorizationFlow.provider
|
(DeviceAuthorizationFlowProvider)(0), // 1: management.DeviceAuthorizationFlow.provider
|
||||||
@ -1571,7 +1681,8 @@ var file_management_proto_goTypes = []interface{}{
|
|||||||
(*DeviceAuthorizationFlowRequest)(nil), // 18: management.DeviceAuthorizationFlowRequest
|
(*DeviceAuthorizationFlowRequest)(nil), // 18: management.DeviceAuthorizationFlowRequest
|
||||||
(*DeviceAuthorizationFlow)(nil), // 19: management.DeviceAuthorizationFlow
|
(*DeviceAuthorizationFlow)(nil), // 19: management.DeviceAuthorizationFlow
|
||||||
(*ProviderConfig)(nil), // 20: management.ProviderConfig
|
(*ProviderConfig)(nil), // 20: management.ProviderConfig
|
||||||
(*timestamp.Timestamp)(nil), // 21: google.protobuf.Timestamp
|
(*Route)(nil), // 21: management.Route
|
||||||
|
(*timestamppb.Timestamp)(nil), // 22: google.protobuf.Timestamp
|
||||||
}
|
}
|
||||||
var file_management_proto_depIdxs = []int32{
|
var file_management_proto_depIdxs = []int32{
|
||||||
11, // 0: management.SyncResponse.wiretrusteeConfig:type_name -> management.WiretrusteeConfig
|
11, // 0: management.SyncResponse.wiretrusteeConfig:type_name -> management.WiretrusteeConfig
|
||||||
@ -1582,7 +1693,7 @@ var file_management_proto_depIdxs = []int32{
|
|||||||
6, // 5: management.LoginRequest.peerKeys:type_name -> management.PeerKeys
|
6, // 5: management.LoginRequest.peerKeys:type_name -> management.PeerKeys
|
||||||
11, // 6: management.LoginResponse.wiretrusteeConfig:type_name -> management.WiretrusteeConfig
|
11, // 6: management.LoginResponse.wiretrusteeConfig:type_name -> management.WiretrusteeConfig
|
||||||
14, // 7: management.LoginResponse.peerConfig:type_name -> management.PeerConfig
|
14, // 7: management.LoginResponse.peerConfig:type_name -> management.PeerConfig
|
||||||
21, // 8: management.ServerKeyResponse.expiresAt:type_name -> google.protobuf.Timestamp
|
22, // 8: management.ServerKeyResponse.expiresAt:type_name -> google.protobuf.Timestamp
|
||||||
12, // 9: management.WiretrusteeConfig.stuns:type_name -> management.HostConfig
|
12, // 9: management.WiretrusteeConfig.stuns:type_name -> management.HostConfig
|
||||||
13, // 10: management.WiretrusteeConfig.turns:type_name -> management.ProtectedHostConfig
|
13, // 10: management.WiretrusteeConfig.turns:type_name -> management.ProtectedHostConfig
|
||||||
12, // 11: management.WiretrusteeConfig.signal:type_name -> management.HostConfig
|
12, // 11: management.WiretrusteeConfig.signal:type_name -> management.HostConfig
|
||||||
@ -1591,24 +1702,25 @@ var file_management_proto_depIdxs = []int32{
|
|||||||
17, // 14: management.PeerConfig.sshConfig:type_name -> management.SSHConfig
|
17, // 14: management.PeerConfig.sshConfig:type_name -> management.SSHConfig
|
||||||
14, // 15: management.NetworkMap.peerConfig:type_name -> management.PeerConfig
|
14, // 15: management.NetworkMap.peerConfig:type_name -> management.PeerConfig
|
||||||
16, // 16: management.NetworkMap.remotePeers:type_name -> management.RemotePeerConfig
|
16, // 16: management.NetworkMap.remotePeers:type_name -> management.RemotePeerConfig
|
||||||
17, // 17: management.RemotePeerConfig.sshConfig:type_name -> management.SSHConfig
|
21, // 17: management.NetworkMap.Routes:type_name -> management.Route
|
||||||
1, // 18: management.DeviceAuthorizationFlow.Provider:type_name -> management.DeviceAuthorizationFlow.provider
|
17, // 18: management.RemotePeerConfig.sshConfig:type_name -> management.SSHConfig
|
||||||
20, // 19: management.DeviceAuthorizationFlow.ProviderConfig:type_name -> management.ProviderConfig
|
1, // 19: management.DeviceAuthorizationFlow.Provider:type_name -> management.DeviceAuthorizationFlow.provider
|
||||||
2, // 20: management.ManagementService.Login:input_type -> management.EncryptedMessage
|
20, // 20: management.DeviceAuthorizationFlow.ProviderConfig:type_name -> management.ProviderConfig
|
||||||
2, // 21: management.ManagementService.Sync:input_type -> management.EncryptedMessage
|
2, // 21: management.ManagementService.Login:input_type -> management.EncryptedMessage
|
||||||
10, // 22: management.ManagementService.GetServerKey:input_type -> management.Empty
|
2, // 22: management.ManagementService.Sync:input_type -> management.EncryptedMessage
|
||||||
10, // 23: management.ManagementService.isHealthy:input_type -> management.Empty
|
10, // 23: management.ManagementService.GetServerKey:input_type -> management.Empty
|
||||||
2, // 24: management.ManagementService.GetDeviceAuthorizationFlow:input_type -> management.EncryptedMessage
|
10, // 24: management.ManagementService.isHealthy:input_type -> management.Empty
|
||||||
2, // 25: management.ManagementService.Login:output_type -> management.EncryptedMessage
|
2, // 25: management.ManagementService.GetDeviceAuthorizationFlow:input_type -> management.EncryptedMessage
|
||||||
2, // 26: management.ManagementService.Sync:output_type -> management.EncryptedMessage
|
2, // 26: management.ManagementService.Login:output_type -> management.EncryptedMessage
|
||||||
9, // 27: management.ManagementService.GetServerKey:output_type -> management.ServerKeyResponse
|
2, // 27: management.ManagementService.Sync:output_type -> management.EncryptedMessage
|
||||||
10, // 28: management.ManagementService.isHealthy:output_type -> management.Empty
|
9, // 28: management.ManagementService.GetServerKey:output_type -> management.ServerKeyResponse
|
||||||
2, // 29: management.ManagementService.GetDeviceAuthorizationFlow:output_type -> management.EncryptedMessage
|
10, // 29: management.ManagementService.isHealthy:output_type -> management.Empty
|
||||||
25, // [25:30] is the sub-list for method output_type
|
2, // 30: management.ManagementService.GetDeviceAuthorizationFlow:output_type -> management.EncryptedMessage
|
||||||
20, // [20:25] is the sub-list for method input_type
|
26, // [26:31] is the sub-list for method output_type
|
||||||
20, // [20:20] is the sub-list for extension type_name
|
21, // [21:26] is the sub-list for method input_type
|
||||||
20, // [20:20] is the sub-list for extension extendee
|
21, // [21:21] is the sub-list for extension type_name
|
||||||
0, // [0:20] is the sub-list for field type_name
|
21, // [21:21] is the sub-list for extension extendee
|
||||||
|
0, // [0:21] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_management_proto_init() }
|
func init() { file_management_proto_init() }
|
||||||
@ -1845,6 +1957,18 @@ func file_management_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
file_management_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*Route); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
@ -1852,7 +1976,7 @@ func file_management_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_management_proto_rawDesc,
|
RawDescriptor: file_management_proto_rawDesc,
|
||||||
NumEnums: 2,
|
NumEnums: 2,
|
||||||
NumMessages: 19,
|
NumMessages: 20,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
|
@ -176,6 +176,8 @@ message NetworkMap {
|
|||||||
// Indicates whether remotePeers array is empty or not to bypass protobuf null and empty array equality.
|
// Indicates whether remotePeers array is empty or not to bypass protobuf null and empty array equality.
|
||||||
bool remotePeersIsEmpty = 4;
|
bool remotePeersIsEmpty = 4;
|
||||||
|
|
||||||
|
// List of routes to be applied
|
||||||
|
repeated Route Routes = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemotePeerConfig represents a configuration of a remote peer.
|
// RemotePeerConfig represents a configuration of a remote peer.
|
||||||
@ -229,3 +231,13 @@ message ProviderConfig {
|
|||||||
// An Audience for validation
|
// An Audience for validation
|
||||||
string Audience = 4;
|
string Audience = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Route represents a route.Route object
|
||||||
|
message Route {
|
||||||
|
string ID = 1;
|
||||||
|
string Prefix = 2;
|
||||||
|
int64 PrefixType = 3;
|
||||||
|
string Peer = 4;
|
||||||
|
int64 Metric = 5;
|
||||||
|
bool Masquerade = 6;
|
||||||
|
}
|
@ -7,6 +7,7 @@ import (
|
|||||||
cacheStore "github.com/eko/gocache/v2/store"
|
cacheStore "github.com/eko/gocache/v2/store"
|
||||||
"github.com/netbirdio/netbird/management/server/idp"
|
"github.com/netbirdio/netbird/management/server/idp"
|
||||||
"github.com/netbirdio/netbird/management/server/jwtclaims"
|
"github.com/netbirdio/netbird/management/server/jwtclaims"
|
||||||
|
"github.com/netbirdio/netbird/route"
|
||||||
gocache "github.com/patrickmn/go-cache"
|
gocache "github.com/patrickmn/go-cache"
|
||||||
"github.com/rs/xid"
|
"github.com/rs/xid"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@ -48,6 +49,7 @@ type AccountManager interface {
|
|||||||
RenamePeer(accountId string, peerKey string, newName string) (*Peer, error)
|
RenamePeer(accountId string, peerKey string, newName string) (*Peer, error)
|
||||||
DeletePeer(accountId string, peerKey string) (*Peer, error)
|
DeletePeer(accountId string, peerKey string) (*Peer, error)
|
||||||
GetPeerByIP(accountId string, peerIP string) (*Peer, error)
|
GetPeerByIP(accountId string, peerIP string) (*Peer, error)
|
||||||
|
UpdatePeer(accountID string, peer *Peer) (*Peer, error)
|
||||||
GetNetworkMap(peerKey string) (*NetworkMap, error)
|
GetNetworkMap(peerKey string) (*NetworkMap, error)
|
||||||
GetPeerNetwork(peerKey string) (*Network, error)
|
GetPeerNetwork(peerKey string) (*Network, error)
|
||||||
AddPeer(setupKey string, userId string, peer *Peer) (*Peer, error)
|
AddPeer(setupKey string, userId string, peer *Peer) (*Peer, error)
|
||||||
@ -67,7 +69,12 @@ type AccountManager interface {
|
|||||||
UpdateRule(accountID string, ruleID string, operations []RuleUpdateOperation) (*Rule, error)
|
UpdateRule(accountID string, ruleID string, operations []RuleUpdateOperation) (*Rule, error)
|
||||||
DeleteRule(accountId, ruleID string) error
|
DeleteRule(accountId, ruleID string) error
|
||||||
ListRules(accountId string) ([]*Rule, error)
|
ListRules(accountId string) ([]*Rule, error)
|
||||||
UpdatePeer(accountID string, peer *Peer) (*Peer, error)
|
GetRoute(accountID, routeID string) (*route.Route, error)
|
||||||
|
CreateRoute(accountID string, prefix, peer, description 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
|
||||||
|
ListRoutes(accountID string) ([]*route.Route, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type DefaultAccountManager struct {
|
type DefaultAccountManager struct {
|
||||||
@ -94,6 +101,7 @@ type Account struct {
|
|||||||
Users map[string]*User
|
Users map[string]*User
|
||||||
Groups map[string]*Group
|
Groups map[string]*Group
|
||||||
Rules map[string]*Rule
|
Rules map[string]*Rule
|
||||||
|
Routes map[string]*route.Route
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserInfo struct {
|
type UserInfo struct {
|
||||||
@ -686,6 +694,7 @@ func newAccountWithId(accountId, userId, domain string) *Account {
|
|||||||
network := NewNetwork()
|
network := NewNetwork()
|
||||||
peers := make(map[string]*Peer)
|
peers := make(map[string]*Peer)
|
||||||
users := make(map[string]*User)
|
users := make(map[string]*User)
|
||||||
|
routes := make(map[string]*route.Route)
|
||||||
users[userId] = NewAdminUser(userId)
|
users[userId] = NewAdminUser(userId)
|
||||||
log.Debugf("created new account %s with setup key %s", accountId, defaultKey.Key)
|
log.Debugf("created new account %s with setup key %s", accountId, defaultKey.Key)
|
||||||
|
|
||||||
@ -697,6 +706,7 @@ func newAccountWithId(accountId, userId, domain string) *Account {
|
|||||||
Users: users,
|
Users: users,
|
||||||
CreatedBy: userId,
|
CreatedBy: userId,
|
||||||
Domain: domain,
|
Domain: domain,
|
||||||
|
Routes: routes,
|
||||||
}
|
}
|
||||||
|
|
||||||
addAllGroup(acc)
|
addAllGroup(acc)
|
||||||
|
@ -2,6 +2,8 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/netbirdio/netbird/route"
|
||||||
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@ -25,6 +27,8 @@ type FileStore struct {
|
|||||||
PrivateDomain2AccountId map[string]string `json:"-"`
|
PrivateDomain2AccountId map[string]string `json:"-"`
|
||||||
PeerKeyId2SrcRulesId map[string]map[string]struct{} `json:"-"`
|
PeerKeyId2SrcRulesId map[string]map[string]struct{} `json:"-"`
|
||||||
PeerKeyId2DstRulesId map[string]map[string]struct{} `json:"-"`
|
PeerKeyId2DstRulesId map[string]map[string]struct{} `json:"-"`
|
||||||
|
PeerKeyID2RouteIDs map[string]map[string]struct{} `json:"-"`
|
||||||
|
AccountPrefix2RouteIDs map[string]map[string][]string `json:"-"`
|
||||||
|
|
||||||
// mutex to synchronise Store read/write operations
|
// mutex to synchronise Store read/write operations
|
||||||
mux sync.Mutex `json:"-"`
|
mux sync.Mutex `json:"-"`
|
||||||
@ -51,7 +55,9 @@ func restore(file string) (*FileStore, error) {
|
|||||||
UserId2AccountId: make(map[string]string),
|
UserId2AccountId: make(map[string]string),
|
||||||
PrivateDomain2AccountId: make(map[string]string),
|
PrivateDomain2AccountId: make(map[string]string),
|
||||||
PeerKeyId2SrcRulesId: make(map[string]map[string]struct{}),
|
PeerKeyId2SrcRulesId: make(map[string]map[string]struct{}),
|
||||||
|
PeerKeyID2RouteIDs: make(map[string]map[string]struct{}),
|
||||||
PeerKeyId2DstRulesId: make(map[string]map[string]struct{}),
|
PeerKeyId2DstRulesId: make(map[string]map[string]struct{}),
|
||||||
|
AccountPrefix2RouteIDs: make(map[string]map[string][]string),
|
||||||
storeFile: file,
|
storeFile: file,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,8 +80,10 @@ func restore(file string) (*FileStore, error) {
|
|||||||
store.PeerKeyId2AccountId = make(map[string]string)
|
store.PeerKeyId2AccountId = make(map[string]string)
|
||||||
store.UserId2AccountId = make(map[string]string)
|
store.UserId2AccountId = make(map[string]string)
|
||||||
store.PrivateDomain2AccountId = make(map[string]string)
|
store.PrivateDomain2AccountId = make(map[string]string)
|
||||||
store.PeerKeyId2SrcRulesId = map[string]map[string]struct{}{}
|
store.PeerKeyId2SrcRulesId = make(map[string]map[string]struct{})
|
||||||
store.PeerKeyId2DstRulesId = map[string]map[string]struct{}{}
|
store.PeerKeyId2DstRulesId = make(map[string]map[string]struct{})
|
||||||
|
store.PeerKeyID2RouteIDs = make(map[string]map[string]struct{})
|
||||||
|
store.AccountPrefix2RouteIDs = make(map[string]map[string][]string)
|
||||||
|
|
||||||
for accountId, account := range store.Accounts {
|
for accountId, account := range store.Accounts {
|
||||||
for setupKeyId := range account.SetupKeys {
|
for setupKeyId := range account.SetupKeys {
|
||||||
@ -116,6 +124,24 @@ func restore(file string) (*FileStore, error) {
|
|||||||
for _, user := range account.Users {
|
for _, user := range account.Users {
|
||||||
store.UserId2AccountId[user.Id] = accountId
|
store.UserId2AccountId[user.Id] = accountId
|
||||||
}
|
}
|
||||||
|
for _, route := range account.Routes {
|
||||||
|
if route.Peer != "" {
|
||||||
|
if store.PeerKeyID2RouteIDs[route.Peer] == nil {
|
||||||
|
store.PeerKeyID2RouteIDs[route.Peer] = make(map[string]struct{})
|
||||||
|
}
|
||||||
|
store.PeerKeyID2RouteIDs[route.Peer][route.ID] = struct{}{}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
store.AccountPrefix2RouteIDs[account.Id][route.Prefix.String()] = append(
|
||||||
|
store.AccountPrefix2RouteIDs[account.Id][route.Prefix.String()],
|
||||||
|
route.ID,
|
||||||
|
)
|
||||||
|
}
|
||||||
if account.Domain != "" && account.DomainCategory == PrivateCategory &&
|
if account.Domain != "" && account.DomainCategory == PrivateCategory &&
|
||||||
account.IsDomainPrimaryAccount {
|
account.IsDomainPrimaryAccount {
|
||||||
store.PrivateDomain2AccountId[account.Domain] = accountId
|
store.PrivateDomain2AccountId[account.Domain] = accountId
|
||||||
@ -177,11 +203,12 @@ func (s *FileStore) DeletePeer(accountId string, peerKey string) (*Peer, error)
|
|||||||
if peer == nil {
|
if peer == nil {
|
||||||
return nil, status.Errorf(codes.NotFound, "peer not found")
|
return nil, status.Errorf(codes.NotFound, "peer not found")
|
||||||
}
|
}
|
||||||
|
peerRoutes := s.PeerKeyID2RouteIDs[peerKey]
|
||||||
delete(account.Peers, peerKey)
|
delete(account.Peers, peerKey)
|
||||||
delete(s.PeerKeyId2AccountId, peerKey)
|
delete(s.PeerKeyId2AccountId, peerKey)
|
||||||
delete(s.PeerKeyId2DstRulesId, peerKey)
|
delete(s.PeerKeyId2DstRulesId, peerKey)
|
||||||
delete(s.PeerKeyId2SrcRulesId, peerKey)
|
delete(s.PeerKeyId2SrcRulesId, peerKey)
|
||||||
|
delete(s.PeerKeyID2RouteIDs, peerKey)
|
||||||
|
|
||||||
// cleanup groups
|
// cleanup groups
|
||||||
for _, g := range account.Groups {
|
for _, g := range account.Groups {
|
||||||
@ -194,6 +221,11 @@ func (s *FileStore) DeletePeer(accountId string, peerKey string) (*Peer, error)
|
|||||||
g.Peers = peers
|
g.Peers = peers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for routeID := range peerRoutes {
|
||||||
|
account.Routes[routeID].Enabled = false
|
||||||
|
account.Routes[routeID].Peer = ""
|
||||||
|
}
|
||||||
|
|
||||||
err = s.persist(s.storeFile)
|
err = s.persist(s.storeFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -238,10 +270,14 @@ func (s *FileStore) SaveAccount(account *Account) error {
|
|||||||
s.SetupKeyId2AccountId[strings.ToUpper(keyId)] = account.Id
|
s.SetupKeyId2AccountId[strings.ToUpper(keyId)] = account.Id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// enforce peer to account index and delete peer to route indexes for rebuild
|
||||||
for _, peer := range account.Peers {
|
for _, peer := range account.Peers {
|
||||||
s.PeerKeyId2AccountId[peer.Key] = account.Id
|
s.PeerKeyId2AccountId[peer.Key] = account.Id
|
||||||
|
delete(s.PeerKeyID2RouteIDs, peer.Key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete(s.AccountPrefix2RouteIDs, account.Id)
|
||||||
|
|
||||||
// remove all peers related to account from rules indexes
|
// remove all peers related to account from rules indexes
|
||||||
cleanIDs := make([]string, 0)
|
cleanIDs := make([]string, 0)
|
||||||
for key := range s.PeerKeyId2SrcRulesId {
|
for key := range s.PeerKeyId2SrcRulesId {
|
||||||
@ -294,6 +330,25 @@ func (s *FileStore) SaveAccount(account *Account) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, route := range account.Routes {
|
||||||
|
if route.Peer != "" {
|
||||||
|
if s.PeerKeyID2RouteIDs[route.Peer] == nil {
|
||||||
|
s.PeerKeyID2RouteIDs[route.Peer] = make(map[string]struct{})
|
||||||
|
}
|
||||||
|
s.PeerKeyID2RouteIDs[route.Peer][route.ID] = struct{}{}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
s.AccountPrefix2RouteIDs[account.Id][route.Prefix.String()] = append(
|
||||||
|
s.AccountPrefix2RouteIDs[account.Id][route.Prefix.String()],
|
||||||
|
route.ID,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
for _, user := range account.Users {
|
for _, user := range account.Users {
|
||||||
s.UserId2AccountId[user.Id] = account.Id
|
s.UserId2AccountId[user.Id] = account.Id
|
||||||
}
|
}
|
||||||
@ -305,6 +360,7 @@ func (s *FileStore) SaveAccount(account *Account) error {
|
|||||||
return s.persist(s.storeFile)
|
return s.persist(s.storeFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAccountByPrivateDomain returns account by private domain
|
||||||
func (s *FileStore) GetAccountByPrivateDomain(domain string) (*Account, error) {
|
func (s *FileStore) GetAccountByPrivateDomain(domain string) (*Account, error) {
|
||||||
accountId, accountIdFound := s.PrivateDomain2AccountId[strings.ToLower(domain)]
|
accountId, accountIdFound := s.PrivateDomain2AccountId[strings.ToLower(domain)]
|
||||||
if !accountIdFound {
|
if !accountIdFound {
|
||||||
@ -322,6 +378,7 @@ func (s *FileStore) GetAccountByPrivateDomain(domain string) (*Account, error) {
|
|||||||
return account, nil
|
return account, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAccountBySetupKey returns account by setup key id
|
||||||
func (s *FileStore) GetAccountBySetupKey(setupKey string) (*Account, error) {
|
func (s *FileStore) GetAccountBySetupKey(setupKey string) (*Account, error) {
|
||||||
accountId, accountIdFound := s.SetupKeyId2AccountId[strings.ToUpper(setupKey)]
|
accountId, accountIdFound := s.SetupKeyId2AccountId[strings.ToUpper(setupKey)]
|
||||||
if !accountIdFound {
|
if !accountIdFound {
|
||||||
@ -336,6 +393,7 @@ func (s *FileStore) GetAccountBySetupKey(setupKey string) (*Account, error) {
|
|||||||
return account, nil
|
return account, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAccountPeers returns account peers
|
||||||
func (s *FileStore) GetAccountPeers(accountId string) ([]*Peer, error) {
|
func (s *FileStore) GetAccountPeers(accountId string) ([]*Peer, error) {
|
||||||
s.mux.Lock()
|
s.mux.Lock()
|
||||||
defer s.mux.Unlock()
|
defer s.mux.Unlock()
|
||||||
@ -353,6 +411,7 @@ func (s *FileStore) GetAccountPeers(accountId string) ([]*Peer, error) {
|
|||||||
return peers, nil
|
return peers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAllAccounts returns all accounts
|
||||||
func (s *FileStore) GetAllAccounts() (all []*Account) {
|
func (s *FileStore) GetAllAccounts() (all []*Account) {
|
||||||
for _, a := range s.Accounts {
|
for _, a := range s.Accounts {
|
||||||
all = append(all, a)
|
all = append(all, a)
|
||||||
@ -361,6 +420,7 @@ func (s *FileStore) GetAllAccounts() (all []*Account) {
|
|||||||
return all
|
return all
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAccount returns an account for id
|
||||||
func (s *FileStore) GetAccount(accountId string) (*Account, error) {
|
func (s *FileStore) GetAccount(accountId string) (*Account, error) {
|
||||||
account, accountFound := s.Accounts[accountId]
|
account, accountFound := s.Accounts[accountId]
|
||||||
if !accountFound {
|
if !accountFound {
|
||||||
@ -370,6 +430,7 @@ func (s *FileStore) GetAccount(accountId string) (*Account, error) {
|
|||||||
return account, nil
|
return account, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserAccount returns a user account
|
||||||
func (s *FileStore) GetUserAccount(userId string) (*Account, error) {
|
func (s *FileStore) GetUserAccount(userId string) (*Account, error) {
|
||||||
s.mux.Lock()
|
s.mux.Lock()
|
||||||
defer s.mux.Unlock()
|
defer s.mux.Unlock()
|
||||||
@ -382,10 +443,7 @@ func (s *FileStore) GetUserAccount(userId string) (*Account, error) {
|
|||||||
return s.GetAccount(accountId)
|
return s.GetAccount(accountId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FileStore) GetPeerAccount(peerKey string) (*Account, error) {
|
func (s *FileStore) getPeerAccount(peerKey string) (*Account, error) {
|
||||||
s.mux.Lock()
|
|
||||||
defer s.mux.Unlock()
|
|
||||||
|
|
||||||
accountId, accountIdFound := s.PeerKeyId2AccountId[peerKey]
|
accountId, accountIdFound := s.PeerKeyId2AccountId[peerKey]
|
||||||
if !accountIdFound {
|
if !accountIdFound {
|
||||||
return nil, status.Errorf(codes.NotFound, "Provided peer key doesn't exists %s", peerKey)
|
return nil, status.Errorf(codes.NotFound, "Provided peer key doesn't exists %s", peerKey)
|
||||||
@ -394,6 +452,15 @@ func (s *FileStore) GetPeerAccount(peerKey string) (*Account, error) {
|
|||||||
return s.GetAccount(accountId)
|
return s.GetAccount(accountId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPeerAccount returns user account if exists
|
||||||
|
func (s *FileStore) GetPeerAccount(peerKey string) (*Account, error) {
|
||||||
|
s.mux.Lock()
|
||||||
|
defer s.mux.Unlock()
|
||||||
|
|
||||||
|
return s.getPeerAccount(peerKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPeerSrcRules return list of source rules for peer
|
||||||
func (s *FileStore) GetPeerSrcRules(accountId, peerKey string) ([]*Rule, error) {
|
func (s *FileStore) GetPeerSrcRules(accountId, peerKey string) ([]*Rule, error) {
|
||||||
s.mux.Lock()
|
s.mux.Lock()
|
||||||
defer s.mux.Unlock()
|
defer s.mux.Unlock()
|
||||||
@ -419,6 +486,7 @@ func (s *FileStore) GetPeerSrcRules(accountId, peerKey string) ([]*Rule, error)
|
|||||||
return rules, nil
|
return rules, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPeerDstRules return list of destination rules for peer
|
||||||
func (s *FileStore) GetPeerDstRules(accountId, peerKey string) ([]*Rule, error) {
|
func (s *FileStore) GetPeerDstRules(accountId, peerKey string) ([]*Rule, error) {
|
||||||
s.mux.Lock()
|
s.mux.Lock()
|
||||||
defer s.mux.Unlock()
|
defer s.mux.Unlock()
|
||||||
@ -443,3 +511,56 @@ func (s *FileStore) GetPeerDstRules(accountId, peerKey string) ([]*Rule, error)
|
|||||||
|
|
||||||
return rules, nil
|
return rules, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPeerRoutes return list of routes for peer
|
||||||
|
func (s *FileStore) GetPeerRoutes(peerKey string) ([]*route.Route, error) {
|
||||||
|
s.mux.Lock()
|
||||||
|
defer s.mux.Unlock()
|
||||||
|
|
||||||
|
account, err := s.getPeerAccount(peerKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var routes []*route.Route
|
||||||
|
|
||||||
|
routeIDs, ok := s.PeerKeyID2RouteIDs[peerKey]
|
||||||
|
if !ok {
|
||||||
|
return routes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for id := range routeIDs {
|
||||||
|
route, found := account.Routes[id]
|
||||||
|
if found {
|
||||||
|
routes = append(routes, route)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return routes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRoutesByPrefix return list of routes by account and route prefix
|
||||||
|
func (s *FileStore) GetRoutesByPrefix(accountID string, prefix netip.Prefix) ([]*route.Route, error) {
|
||||||
|
s.mux.Lock()
|
||||||
|
defer s.mux.Unlock()
|
||||||
|
|
||||||
|
account, err := s.GetAccount(accountID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
routeIDs, ok := s.AccountPrefix2RouteIDs[accountID][prefix.String()]
|
||||||
|
if !ok {
|
||||||
|
return nil, status.Errorf(codes.NotFound, "no routes for prefix: %v", prefix.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
var routes []*route.Route
|
||||||
|
for _, id := range routeIDs {
|
||||||
|
route, found := account.Routes[id]
|
||||||
|
if found {
|
||||||
|
routes = append(routes, route)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return routes, nil
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ package server
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/netbirdio/netbird/route"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -230,7 +231,7 @@ func (s *GRPCServer) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest)
|
|||||||
peersToSend = append(peersToSend, p)
|
peersToSend = append(peersToSend, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
update := toSyncResponse(s.config, remotePeer, peersToSend, nil, networkMap.Network.CurrentSerial(), networkMap.Network)
|
update := toSyncResponse(s.config, remotePeer, peersToSend, networkMap.Routes, nil, networkMap.Network.CurrentSerial(), networkMap.Network)
|
||||||
err = s.peersUpdateManager.SendUpdate(remotePeer.Key, &UpdateMessage{Update: update})
|
err = s.peersUpdateManager.SendUpdate(remotePeer.Key, &UpdateMessage{Update: update})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// todo rethink if we should keep this return
|
// todo rethink if we should keep this return
|
||||||
@ -407,13 +408,15 @@ func toRemotePeerConfig(peers []*Peer) []*proto.RemotePeerConfig {
|
|||||||
return remotePeers
|
return remotePeers
|
||||||
}
|
}
|
||||||
|
|
||||||
func toSyncResponse(config *Config, peer *Peer, peers []*Peer, turnCredentials *TURNCredentials, serial uint64, network *Network) *proto.SyncResponse {
|
func toSyncResponse(config *Config, peer *Peer, peers []*Peer, routes []*route.Route, turnCredentials *TURNCredentials, serial uint64, network *Network) *proto.SyncResponse {
|
||||||
wtConfig := toWiretrusteeConfig(config, turnCredentials)
|
wtConfig := toWiretrusteeConfig(config, turnCredentials)
|
||||||
|
|
||||||
pConfig := toPeerConfig(peer, network)
|
pConfig := toPeerConfig(peer, network)
|
||||||
|
|
||||||
remotePeers := toRemotePeerConfig(peers)
|
remotePeers := toRemotePeerConfig(peers)
|
||||||
|
|
||||||
|
routesUpdate := toProtocolRoutes(routes)
|
||||||
|
|
||||||
return &proto.SyncResponse{
|
return &proto.SyncResponse{
|
||||||
WiretrusteeConfig: wtConfig,
|
WiretrusteeConfig: wtConfig,
|
||||||
PeerConfig: pConfig,
|
PeerConfig: pConfig,
|
||||||
@ -424,6 +427,7 @@ func toSyncResponse(config *Config, peer *Peer, peers []*Peer, turnCredentials *
|
|||||||
PeerConfig: pConfig,
|
PeerConfig: pConfig,
|
||||||
RemotePeers: remotePeers,
|
RemotePeers: remotePeers,
|
||||||
RemotePeersIsEmpty: len(remotePeers) == 0,
|
RemotePeersIsEmpty: len(remotePeers) == 0,
|
||||||
|
Routes: routesUpdate,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -449,7 +453,7 @@ func (s *GRPCServer) sendInitialSync(peerKey wgtypes.Key, peer *Peer, srv proto.
|
|||||||
} else {
|
} else {
|
||||||
turnCredentials = nil
|
turnCredentials = nil
|
||||||
}
|
}
|
||||||
plainResp := toSyncResponse(s.config, peer, networkMap.Peers, turnCredentials, networkMap.Network.CurrentSerial(), networkMap.Network)
|
plainResp := toSyncResponse(s.config, peer, networkMap.Peers, networkMap.Routes, turnCredentials, networkMap.Network.CurrentSerial(), networkMap.Network)
|
||||||
|
|
||||||
encryptedResp, err := encryption.EncryptMessage(peerKey, s.wgKey, plainResp)
|
encryptedResp, err := encryption.EncryptMessage(peerKey, s.wgKey, plainResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -3,6 +3,7 @@ package mock_server
|
|||||||
import (
|
import (
|
||||||
"github.com/netbirdio/netbird/management/server"
|
"github.com/netbirdio/netbird/management/server"
|
||||||
"github.com/netbirdio/netbird/management/server/jwtclaims"
|
"github.com/netbirdio/netbird/management/server/jwtclaims"
|
||||||
|
"github.com/netbirdio/netbird/route"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
"time"
|
"time"
|
||||||
@ -44,6 +45,12 @@ type MockAccountManager struct {
|
|||||||
UpdatePeerMetaFunc func(peerKey string, meta server.PeerSystemMeta) error
|
UpdatePeerMetaFunc func(peerKey string, meta server.PeerSystemMeta) error
|
||||||
UpdatePeerSSHKeyFunc func(peerKey string, sshKey string) error
|
UpdatePeerSSHKeyFunc func(peerKey string, sshKey string) error
|
||||||
UpdatePeerFunc func(accountID string, peer *server.Peer) (*server.Peer, 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)
|
||||||
|
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)
|
||||||
|
DeleteRouteFunc func(accountID, routeID string) error
|
||||||
|
ListRoutesFunc func(accountID string) ([]*route.Route, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUsersFromAccount mock implementation of GetUsersFromAccount from server.AccountManager interface
|
// GetUsersFromAccount mock implementation of GetUsersFromAccount from server.AccountManager interface
|
||||||
@ -360,3 +367,51 @@ func (am *MockAccountManager) UpdatePeer(accountID string, peer *server.Peer) (*
|
|||||||
}
|
}
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method UpdatePeerFunc is is not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method UpdatePeerFunc is is not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
if am.GetRouteFunc != nil {
|
||||||
|
return am.CreateRouteFunc(accountID, prefix, peer, description, masquerade, metric, enabled)
|
||||||
|
}
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method CreateRoute is not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRoute mock implementation of GetRoute from server.AccountManager interface
|
||||||
|
func (am *MockAccountManager) GetRoute(accountID, routeID string) (*route.Route, error) {
|
||||||
|
if am.GetRouteFunc != nil {
|
||||||
|
return am.GetRouteFunc(accountID, routeID)
|
||||||
|
}
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method GetRoute is not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveRoute mock implementation of SaveRoute from server.AccountManager interface
|
||||||
|
func (am *MockAccountManager) SaveRoute(accountID string, route *route.Route) error {
|
||||||
|
if am.SaveRouteFunc != nil {
|
||||||
|
return am.SaveRouteFunc(accountID, route)
|
||||||
|
}
|
||||||
|
return status.Errorf(codes.Unimplemented, "method SaveRoute is not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRoute mock implementation of UpdateRoute from server.AccountManager interface
|
||||||
|
func (am *MockAccountManager) UpdateRoute(accountID string, ruleID string, operations []server.RouteUpdateOperation) (*route.Route, error) {
|
||||||
|
if am.UpdateRouteFunc != nil {
|
||||||
|
return am.UpdateRouteFunc(accountID, ruleID, operations)
|
||||||
|
}
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method UpdateRoute not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRoute mock implementation of DeleteRoute from server.AccountManager interface
|
||||||
|
func (am *MockAccountManager) DeleteRoute(accountID, routeID string) error {
|
||||||
|
if am.DeleteRouteFunc != nil {
|
||||||
|
return am.DeleteRouteFunc(accountID, routeID)
|
||||||
|
}
|
||||||
|
return status.Errorf(codes.Unimplemented, "method DeleteRoute is not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListRoutes mock implementation of ListRoutes from server.AccountManager interface
|
||||||
|
func (am *MockAccountManager) ListRoutes(accountID string) ([]*route.Route, error) {
|
||||||
|
if am.ListRoutesFunc != nil {
|
||||||
|
return am.ListRoutesFunc(accountID)
|
||||||
|
}
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method ListRoutes is not implemented")
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/c-robinson/iplib"
|
"github.com/c-robinson/iplib"
|
||||||
|
"github.com/netbirdio/netbird/route"
|
||||||
"github.com/rs/xid"
|
"github.com/rs/xid"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
@ -24,6 +25,7 @@ const (
|
|||||||
type NetworkMap struct {
|
type NetworkMap struct {
|
||||||
Peers []*Peer
|
Peers []*Peer
|
||||||
Network *Network
|
Network *Network
|
||||||
|
Routes []*route.Route
|
||||||
}
|
}
|
||||||
|
|
||||||
type Network struct {
|
type Network struct {
|
||||||
|
@ -251,9 +251,13 @@ func (am *DefaultAccountManager) GetNetworkMap(peerKey string) (*NetworkMap, err
|
|||||||
return nil, status.Errorf(codes.Internal, "Invalid peer key %s", peerKey)
|
return nil, status.Errorf(codes.Internal, "Invalid peer key %s", peerKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aclPeers := am.getPeersByACL(account, peerKey)
|
||||||
|
routesUpdate := am.getPeersRoutes(append(aclPeers, account.Peers[peerKey]))
|
||||||
|
|
||||||
return &NetworkMap{
|
return &NetworkMap{
|
||||||
Peers: am.getPeersByACL(account, peerKey),
|
Peers: aclPeers,
|
||||||
Network: account.Network.Copy(),
|
Network: account.Network.Copy(),
|
||||||
|
Routes: routesUpdate,
|
||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -508,20 +512,23 @@ func (am *DefaultAccountManager) updateAccountPeers(account *Account) error {
|
|||||||
|
|
||||||
network := account.Network.Copy()
|
network := account.Network.Copy()
|
||||||
|
|
||||||
for _, p := range peers {
|
for _, peer := range peers {
|
||||||
update := toRemotePeerConfig(am.getPeersByACL(account, p.Key))
|
aclPeers := am.getPeersByACL(account, peer.Key)
|
||||||
err = am.peersUpdateManager.SendUpdate(p.Key,
|
peersUpdate := toRemotePeerConfig(aclPeers)
|
||||||
|
routesUpdate := toProtocolRoutes(am.getPeersRoutes(append(aclPeers, peer)))
|
||||||
|
err = am.peersUpdateManager.SendUpdate(peer.Key,
|
||||||
&UpdateMessage{
|
&UpdateMessage{
|
||||||
Update: &proto.SyncResponse{
|
Update: &proto.SyncResponse{
|
||||||
// fill deprecated fields for backward compatibility
|
// fill deprecated fields for backward compatibility
|
||||||
RemotePeers: update,
|
RemotePeers: peersUpdate,
|
||||||
RemotePeersIsEmpty: len(update) == 0,
|
RemotePeersIsEmpty: len(peersUpdate) == 0,
|
||||||
// new field
|
// new field
|
||||||
NetworkMap: &proto.NetworkMap{
|
NetworkMap: &proto.NetworkMap{
|
||||||
Serial: account.Network.CurrentSerial(),
|
Serial: account.Network.CurrentSerial(),
|
||||||
RemotePeers: update,
|
RemotePeers: peersUpdate,
|
||||||
RemotePeersIsEmpty: len(update) == 0,
|
RemotePeersIsEmpty: len(peersUpdate) == 0,
|
||||||
PeerConfig: toPeerConfig(p, network),
|
PeerConfig: toPeerConfig(peer, network),
|
||||||
|
Routes: routesUpdate,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
362
management/server/route.go
Normal file
362
management/server/route.go
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/netbirdio/netbird/management/proto"
|
||||||
|
"github.com/netbirdio/netbird/route"
|
||||||
|
"github.com/rs/xid"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
"net/netip"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// UpdateRouteDescription indicates a route description update operation
|
||||||
|
UpdateRouteDescription RouteUpdateOperationType = iota
|
||||||
|
// UpdateRoutePrefix indicates a route IP update operation
|
||||||
|
UpdateRoutePrefix
|
||||||
|
// UpdateRoutePeer indicates a route peer update operation
|
||||||
|
UpdateRoutePeer
|
||||||
|
// UpdateRouteMetric indicates a route metric update operation
|
||||||
|
UpdateRouteMetric
|
||||||
|
// UpdateRouteMasquerade indicates a route masquerade update operation
|
||||||
|
UpdateRouteMasquerade
|
||||||
|
// UpdateRouteEnabled indicates a route enabled update operation
|
||||||
|
UpdateRouteEnabled
|
||||||
|
)
|
||||||
|
|
||||||
|
// RouteUpdateOperationType operation type
|
||||||
|
type RouteUpdateOperationType int
|
||||||
|
|
||||||
|
func (t RouteUpdateOperationType) String() string {
|
||||||
|
switch t {
|
||||||
|
case UpdateRouteDescription:
|
||||||
|
return "UpdateRouteDescription"
|
||||||
|
case UpdateRoutePrefix:
|
||||||
|
return "UpdateRoutePrefix"
|
||||||
|
case UpdateRoutePeer:
|
||||||
|
return "UpdateRoutePeer"
|
||||||
|
case UpdateRouteMetric:
|
||||||
|
return "UpdateRouteMetric"
|
||||||
|
case UpdateRouteMasquerade:
|
||||||
|
return "UpdateRouteMasquerade"
|
||||||
|
case UpdateRouteEnabled:
|
||||||
|
return "UpdateRouteEnabled"
|
||||||
|
default:
|
||||||
|
return "InvalidOperation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RouteUpdateOperation operation object with type and values to be applied
|
||||||
|
type RouteUpdateOperation struct {
|
||||||
|
Type RouteUpdateOperationType
|
||||||
|
Values []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRoute gets a route object from account and route IDs
|
||||||
|
func (am *DefaultAccountManager) GetRoute(accountID, routeID string) (*route.Route, error) {
|
||||||
|
am.mux.Lock()
|
||||||
|
defer am.mux.Unlock()
|
||||||
|
|
||||||
|
account, err := am.Store.GetAccount(accountID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.NotFound, "account not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
wantedRoute, found := account.Routes[routeID]
|
||||||
|
if found {
|
||||||
|
return wantedRoute, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
func (am *DefaultAccountManager) checkPrefixPeerExists(accountID, peer string, prefix netip.Prefix) error {
|
||||||
|
routesWithPrefix, err := am.Store.GetRoutesByPrefix(accountID, prefix)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if s, ok := status.FromError(err); ok && s.Code() == codes.NotFound {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return status.Errorf(codes.InvalidArgument, "failed to parse prefix %s", prefix.String())
|
||||||
|
}
|
||||||
|
for _, prefixRoute := range routesWithPrefix {
|
||||||
|
if prefixRoute.Peer == peer {
|
||||||
|
return status.Errorf(codes.AlreadyExists, "failed a route with prefix %s and peer already exist", prefix.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
am.mux.Lock()
|
||||||
|
defer am.mux.Unlock()
|
||||||
|
|
||||||
|
account, err := am.Store.GetAccount(accountID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.NotFound, "account not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
var newRoute route.Route
|
||||||
|
prefixType, newPrefix, err := route.ParsePrefix(prefix)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, "failed to parse IP %s", prefix)
|
||||||
|
}
|
||||||
|
err = am.checkPrefixPeerExists(accountID, peer, newPrefix)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if peer != "" {
|
||||||
|
_, peerExist := account.Peers[peer]
|
||||||
|
if !peerExist {
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, "failed to find Peer %s", peer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if metric < route.MinMetric || metric > route.MaxMetric {
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, "metric should be between %d and %d", route.MinMetric, route.MaxMetric)
|
||||||
|
}
|
||||||
|
|
||||||
|
newRoute.Peer = peer
|
||||||
|
newRoute.ID = xid.New().String()
|
||||||
|
newRoute.Prefix = newPrefix
|
||||||
|
newRoute.PrefixType = prefixType
|
||||||
|
newRoute.Description = description
|
||||||
|
newRoute.Masquerade = masquerade
|
||||||
|
newRoute.Metric = metric
|
||||||
|
newRoute.Enabled = enabled
|
||||||
|
|
||||||
|
if account.Routes == nil {
|
||||||
|
account.Routes = make(map[string]*route.Route)
|
||||||
|
}
|
||||||
|
|
||||||
|
account.Routes[newRoute.ID] = &newRoute
|
||||||
|
|
||||||
|
account.Network.IncSerial()
|
||||||
|
if err = am.Store.SaveAccount(account); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = am.updateAccountPeers(account)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return &newRoute, status.Errorf(codes.Unavailable, "failed to update peers after create route %s", newPrefix)
|
||||||
|
}
|
||||||
|
return &newRoute, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveRoute saves route
|
||||||
|
func (am *DefaultAccountManager) SaveRoute(accountID string, routeToSave *route.Route) error {
|
||||||
|
am.mux.Lock()
|
||||||
|
defer am.mux.Unlock()
|
||||||
|
|
||||||
|
if routeToSave == nil {
|
||||||
|
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.Metric < route.MinMetric || routeToSave.Metric > route.MaxMetric {
|
||||||
|
return status.Errorf(codes.InvalidArgument, "metric should be between %d and %d", route.MinMetric, route.MaxMetric)
|
||||||
|
}
|
||||||
|
|
||||||
|
account, err := am.Store.GetAccount(accountID)
|
||||||
|
if err != nil {
|
||||||
|
return status.Errorf(codes.NotFound, "account not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if routeToSave.Peer != "" {
|
||||||
|
_, peerExist := account.Peers[routeToSave.Peer]
|
||||||
|
if !peerExist {
|
||||||
|
return status.Errorf(codes.InvalidArgument, "failed to find Peer %s", routeToSave.Peer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
account.Routes[routeToSave.ID] = routeToSave
|
||||||
|
|
||||||
|
account.Network.IncSerial()
|
||||||
|
if err = am.Store.SaveAccount(account); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return am.updateAccountPeers(account)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRoute updates existing route with set of operations
|
||||||
|
func (am *DefaultAccountManager) UpdateRoute(accountID, routeID string, operations []RouteUpdateOperation) (*route.Route, error) {
|
||||||
|
am.mux.Lock()
|
||||||
|
defer am.mux.Unlock()
|
||||||
|
|
||||||
|
account, err := am.Store.GetAccount(accountID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.NotFound, "account not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
routeToUpdate, ok := account.Routes[routeID]
|
||||||
|
if !ok {
|
||||||
|
return nil, status.Errorf(codes.NotFound, "route %s no longer exists", routeID)
|
||||||
|
}
|
||||||
|
|
||||||
|
newRoute := routeToUpdate.Copy()
|
||||||
|
|
||||||
|
for _, operation := range operations {
|
||||||
|
|
||||||
|
if len(operation.Values) != 1 {
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, "operation %s contains invalid number of values, it should be 1", operation.Type.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
switch operation.Type {
|
||||||
|
case UpdateRouteDescription:
|
||||||
|
newRoute.Description = operation.Values[0]
|
||||||
|
case UpdateRoutePrefix:
|
||||||
|
prefixType, prefix, err := route.ParsePrefix(operation.Values[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, "failed to parse IP %s", operation.Values[0])
|
||||||
|
}
|
||||||
|
err = am.checkPrefixPeerExists(accountID, routeToUpdate.Peer, prefix)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newRoute.Prefix = prefix
|
||||||
|
newRoute.PrefixType = prefixType
|
||||||
|
case UpdateRoutePeer:
|
||||||
|
if operation.Values[0] != "" {
|
||||||
|
_, peerExist := account.Peers[operation.Values[0]]
|
||||||
|
if !peerExist {
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, "failed to find Peer %s", operation.Values[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = am.checkPrefixPeerExists(accountID, operation.Values[0], routeToUpdate.Prefix)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newRoute.Peer = operation.Values[0]
|
||||||
|
case UpdateRouteMetric:
|
||||||
|
metric, err := strconv.Atoi(operation.Values[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, "failed to parse metric %s, not int", operation.Values[0])
|
||||||
|
}
|
||||||
|
if metric < route.MinMetric || metric > route.MaxMetric {
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, "failed to parse metric %s, value should be %d > N < %d",
|
||||||
|
operation.Values[0],
|
||||||
|
route.MinMetric,
|
||||||
|
route.MaxMetric,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
newRoute.Metric = metric
|
||||||
|
case UpdateRouteMasquerade:
|
||||||
|
masquerade, err := strconv.ParseBool(operation.Values[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, "failed to parse masquerade %s, not boolean", operation.Values[0])
|
||||||
|
}
|
||||||
|
newRoute.Masquerade = masquerade
|
||||||
|
case UpdateRouteEnabled:
|
||||||
|
enabled, err := strconv.ParseBool(operation.Values[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, "failed to parse enabled %s, not boolean", operation.Values[0])
|
||||||
|
}
|
||||||
|
newRoute.Enabled = enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
account.Routes[routeID] = newRoute
|
||||||
|
|
||||||
|
account.Network.IncSerial()
|
||||||
|
if err = am.Store.SaveAccount(account); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = am.updateAccountPeers(account)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "failed to update account peers")
|
||||||
|
}
|
||||||
|
return newRoute, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRoute deletes route with routeID
|
||||||
|
func (am *DefaultAccountManager) DeleteRoute(accountID, routeID string) error {
|
||||||
|
am.mux.Lock()
|
||||||
|
defer am.mux.Unlock()
|
||||||
|
|
||||||
|
account, err := am.Store.GetAccount(accountID)
|
||||||
|
if err != nil {
|
||||||
|
return status.Errorf(codes.NotFound, "account not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(account.Routes, routeID)
|
||||||
|
|
||||||
|
account.Network.IncSerial()
|
||||||
|
if err = am.Store.SaveAccount(account); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return am.updateAccountPeers(account)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListRoutes returns a list of routes from account
|
||||||
|
func (am *DefaultAccountManager) ListRoutes(accountID string) ([]*route.Route, error) {
|
||||||
|
am.mux.Lock()
|
||||||
|
defer am.mux.Unlock()
|
||||||
|
|
||||||
|
account, err := am.Store.GetAccount(accountID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.NotFound, "account not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
routes := make([]*route.Route, 0, len(account.Routes))
|
||||||
|
for _, item := range account.Routes {
|
||||||
|
routes = append(routes, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return routes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (am *DefaultAccountManager) getPeersRoutes(peers []*Peer) []*route.Route {
|
||||||
|
routes := make([]*route.Route, 0)
|
||||||
|
for _, peer := range peers {
|
||||||
|
peerRoutes, err := am.Store.GetPeerRoutes(peer.Key)
|
||||||
|
if err != nil {
|
||||||
|
errorStatus, ok := status.FromError(err)
|
||||||
|
if !ok && errorStatus.Code() != codes.NotFound {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
activeRoutes := make([]*route.Route, 0)
|
||||||
|
for _, pr := range peerRoutes {
|
||||||
|
if pr.Enabled {
|
||||||
|
activeRoutes = append(activeRoutes, pr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(activeRoutes) > 0 {
|
||||||
|
routes = append(routes, activeRoutes...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return routes
|
||||||
|
}
|
||||||
|
|
||||||
|
func toProtocolRoutes(routes []*route.Route) []*proto.Route {
|
||||||
|
protoRoutes := make([]*proto.Route, 0)
|
||||||
|
for _, r := range routes {
|
||||||
|
protoRoutes = append(protoRoutes, toProtocolRoute(r))
|
||||||
|
}
|
||||||
|
return protoRoutes
|
||||||
|
}
|
751
management/server/route_test.go
Normal file
751
management/server/route_test.go
Normal file
@ -0,0 +1,751 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/netbirdio/netbird/route"
|
||||||
|
"github.com/rs/xid"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"net/netip"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
const peer1Key = "BhRPtynAAYRDy08+q4HTMsos8fs4plTP4NOSh7C1ry8="
|
||||||
|
const peer2Key = "/yF0+vCfv+mRR5k0dca0TrGdO/oiNeAI58gToZm5NyI="
|
||||||
|
|
||||||
|
func TestCreateRoute(t *testing.T) {
|
||||||
|
|
||||||
|
type input struct {
|
||||||
|
prefix string
|
||||||
|
peer string
|
||||||
|
description string
|
||||||
|
masquerade bool
|
||||||
|
metric int
|
||||||
|
enabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
inputArgs input
|
||||||
|
shouldCreate bool
|
||||||
|
errFunc require.ErrorAssertionFunc
|
||||||
|
expectedRoute *route.Route
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Happy Path",
|
||||||
|
inputArgs: input{
|
||||||
|
prefix: "192.168.0.0/16",
|
||||||
|
peer: peer1Key,
|
||||||
|
description: "super",
|
||||||
|
masquerade: false,
|
||||||
|
metric: 9999,
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
errFunc: require.NoError,
|
||||||
|
shouldCreate: true,
|
||||||
|
expectedRoute: &route.Route{
|
||||||
|
Prefix: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
|
PrefixType: route.IPv4Prefix,
|
||||||
|
Peer: peer1Key,
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bad Prefix",
|
||||||
|
inputArgs: input{
|
||||||
|
prefix: "192.168.0.0/34",
|
||||||
|
peer: peer1Key,
|
||||||
|
description: "super",
|
||||||
|
masquerade: false,
|
||||||
|
metric: 9999,
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
errFunc: require.Error,
|
||||||
|
shouldCreate: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bad Peer",
|
||||||
|
inputArgs: input{
|
||||||
|
prefix: "192.168.0.0/16",
|
||||||
|
peer: "notExistingPeer",
|
||||||
|
description: "super",
|
||||||
|
masquerade: false,
|
||||||
|
metric: 9999,
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
errFunc: require.Error,
|
||||||
|
shouldCreate: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty Peer",
|
||||||
|
inputArgs: input{
|
||||||
|
prefix: "192.168.0.0/16",
|
||||||
|
peer: "",
|
||||||
|
description: "super",
|
||||||
|
masquerade: false,
|
||||||
|
metric: 9999,
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
errFunc: require.NoError,
|
||||||
|
shouldCreate: true,
|
||||||
|
expectedRoute: &route.Route{
|
||||||
|
Prefix: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
|
PrefixType: route.IPv4Prefix,
|
||||||
|
Peer: "",
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Large Metric",
|
||||||
|
inputArgs: input{
|
||||||
|
prefix: "192.168.0.0/16",
|
||||||
|
peer: peer1Key,
|
||||||
|
description: "super",
|
||||||
|
masquerade: false,
|
||||||
|
metric: 99999,
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
errFunc: require.Error,
|
||||||
|
shouldCreate: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Small Metric",
|
||||||
|
inputArgs: input{
|
||||||
|
prefix: "192.168.0.0/16",
|
||||||
|
peer: peer1Key,
|
||||||
|
description: "super",
|
||||||
|
masquerade: false,
|
||||||
|
metric: 0,
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
errFunc: require.Error,
|
||||||
|
shouldCreate: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
|
am, err := createRouterManager(t)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("failed to create account manager")
|
||||||
|
}
|
||||||
|
|
||||||
|
account, err := initTestRouteAccount(t, am)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("failed to init testing account")
|
||||||
|
}
|
||||||
|
|
||||||
|
outRoute, err := am.CreateRoute(
|
||||||
|
account.Id,
|
||||||
|
testCase.inputArgs.prefix,
|
||||||
|
testCase.inputArgs.peer,
|
||||||
|
testCase.inputArgs.description,
|
||||||
|
testCase.inputArgs.masquerade,
|
||||||
|
testCase.inputArgs.metric,
|
||||||
|
testCase.inputArgs.enabled,
|
||||||
|
)
|
||||||
|
|
||||||
|
testCase.errFunc(t, err)
|
||||||
|
|
||||||
|
if !testCase.shouldCreate {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// assign generated ID
|
||||||
|
testCase.expectedRoute.ID = outRoute.ID
|
||||||
|
|
||||||
|
if !testCase.expectedRoute.IsEqual(outRoute) {
|
||||||
|
t.Errorf("new route didn't match expected route:\nGot %#v\nExpected:%#v\n", outRoute, testCase.expectedRoute)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSaveRoute(t *testing.T) {
|
||||||
|
|
||||||
|
validPeer := peer2Key
|
||||||
|
invalidPeer := "nonExisting"
|
||||||
|
validPrefix := netip.MustParsePrefix("192.168.0.0/24")
|
||||||
|
invalidPrefix, _ := netip.ParsePrefix("192.168.0.0/34")
|
||||||
|
validMetric := 1000
|
||||||
|
invalidMetric := 99999
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
existingRoute *route.Route
|
||||||
|
newPeer *string
|
||||||
|
newMetric *int
|
||||||
|
newPrefix *netip.Prefix
|
||||||
|
skipCopying bool
|
||||||
|
shouldCreate bool
|
||||||
|
errFunc require.ErrorAssertionFunc
|
||||||
|
expectedRoute *route.Route
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Happy Path",
|
||||||
|
existingRoute: &route.Route{
|
||||||
|
ID: "testingRoute",
|
||||||
|
Prefix: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
|
PrefixType: route.IPv4Prefix,
|
||||||
|
Peer: peer1Key,
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
newPeer: &validPeer,
|
||||||
|
newMetric: &validMetric,
|
||||||
|
newPrefix: &validPrefix,
|
||||||
|
errFunc: require.NoError,
|
||||||
|
shouldCreate: true,
|
||||||
|
expectedRoute: &route.Route{
|
||||||
|
ID: "testingRoute",
|
||||||
|
Prefix: validPrefix,
|
||||||
|
PrefixType: route.IPv4Prefix,
|
||||||
|
Peer: validPeer,
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: validMetric,
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bad Prefix",
|
||||||
|
existingRoute: &route.Route{
|
||||||
|
ID: "testingRoute",
|
||||||
|
Prefix: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
|
PrefixType: route.IPv4Prefix,
|
||||||
|
Peer: peer1Key,
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
newPrefix: &invalidPrefix,
|
||||||
|
errFunc: require.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bad Peer",
|
||||||
|
existingRoute: &route.Route{
|
||||||
|
ID: "testingRoute",
|
||||||
|
Prefix: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
|
PrefixType: route.IPv4Prefix,
|
||||||
|
Peer: peer1Key,
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
newPeer: &invalidPeer,
|
||||||
|
errFunc: require.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid Metric",
|
||||||
|
existingRoute: &route.Route{
|
||||||
|
ID: "testingRoute",
|
||||||
|
Prefix: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
|
PrefixType: route.IPv4Prefix,
|
||||||
|
Peer: peer1Key,
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
newMetric: &invalidMetric,
|
||||||
|
errFunc: require.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Nil Route",
|
||||||
|
existingRoute: &route.Route{
|
||||||
|
ID: "testingRoute",
|
||||||
|
Prefix: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
|
PrefixType: route.IPv4Prefix,
|
||||||
|
Peer: peer1Key,
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
skipCopying: true,
|
||||||
|
errFunc: require.Error,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
|
am, err := createRouterManager(t)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("failed to create account manager")
|
||||||
|
}
|
||||||
|
|
||||||
|
account, err := initTestRouteAccount(t, am)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("failed to init testing account")
|
||||||
|
}
|
||||||
|
|
||||||
|
account.Routes[testCase.existingRoute.ID] = testCase.existingRoute
|
||||||
|
|
||||||
|
err = am.Store.SaveAccount(account)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("account should be saved")
|
||||||
|
}
|
||||||
|
|
||||||
|
var routeToSave *route.Route
|
||||||
|
|
||||||
|
if !testCase.skipCopying {
|
||||||
|
routeToSave = testCase.existingRoute.Copy()
|
||||||
|
if testCase.newPeer != nil {
|
||||||
|
routeToSave.Peer = *testCase.newPeer
|
||||||
|
}
|
||||||
|
|
||||||
|
if testCase.newMetric != nil {
|
||||||
|
routeToSave.Metric = *testCase.newMetric
|
||||||
|
}
|
||||||
|
|
||||||
|
if testCase.newPrefix != nil {
|
||||||
|
routeToSave.Prefix = *testCase.newPrefix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = am.SaveRoute(account.Id, routeToSave)
|
||||||
|
|
||||||
|
testCase.errFunc(t, err)
|
||||||
|
|
||||||
|
if !testCase.shouldCreate {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
savedRoute, saved := account.Routes[testCase.expectedRoute.ID]
|
||||||
|
require.True(t, saved)
|
||||||
|
|
||||||
|
if !testCase.expectedRoute.IsEqual(savedRoute) {
|
||||||
|
t.Errorf("new route didn't match expected route:\nGot %#v\nExpected:%#v\n", savedRoute, testCase.expectedRoute)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateRoute(t *testing.T) {
|
||||||
|
routeID := "testingRouteID"
|
||||||
|
|
||||||
|
existingRoute := &route.Route{
|
||||||
|
ID: routeID,
|
||||||
|
Prefix: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
|
PrefixType: route.IPv4Prefix,
|
||||||
|
Peer: peer1Key,
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
existingRoute *route.Route
|
||||||
|
operations []RouteUpdateOperation
|
||||||
|
shouldCreate bool
|
||||||
|
errFunc require.ErrorAssertionFunc
|
||||||
|
expectedRoute *route.Route
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Happy Path Single OPS",
|
||||||
|
existingRoute: existingRoute,
|
||||||
|
operations: []RouteUpdateOperation{
|
||||||
|
RouteUpdateOperation{
|
||||||
|
Type: UpdateRoutePeer,
|
||||||
|
Values: []string{peer2Key},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errFunc: require.NoError,
|
||||||
|
shouldCreate: true,
|
||||||
|
expectedRoute: &route.Route{
|
||||||
|
ID: routeID,
|
||||||
|
Prefix: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
|
PrefixType: route.IPv4Prefix,
|
||||||
|
Peer: peer2Key,
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Happy Path Multiple OPS",
|
||||||
|
existingRoute: existingRoute,
|
||||||
|
operations: []RouteUpdateOperation{
|
||||||
|
RouteUpdateOperation{
|
||||||
|
Type: UpdateRouteDescription,
|
||||||
|
Values: []string{"great"},
|
||||||
|
},
|
||||||
|
RouteUpdateOperation{
|
||||||
|
Type: UpdateRoutePrefix,
|
||||||
|
Values: []string{"192.168.0.0/24"},
|
||||||
|
},
|
||||||
|
RouteUpdateOperation{
|
||||||
|
Type: UpdateRoutePeer,
|
||||||
|
Values: []string{peer2Key},
|
||||||
|
},
|
||||||
|
RouteUpdateOperation{
|
||||||
|
Type: UpdateRouteMetric,
|
||||||
|
Values: []string{"3030"},
|
||||||
|
},
|
||||||
|
RouteUpdateOperation{
|
||||||
|
Type: UpdateRouteMasquerade,
|
||||||
|
Values: []string{"true"},
|
||||||
|
},
|
||||||
|
RouteUpdateOperation{
|
||||||
|
Type: UpdateRouteEnabled,
|
||||||
|
Values: []string{"false"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errFunc: require.NoError,
|
||||||
|
shouldCreate: true,
|
||||||
|
expectedRoute: &route.Route{
|
||||||
|
ID: routeID,
|
||||||
|
Prefix: netip.MustParsePrefix("192.168.0.0/24"),
|
||||||
|
PrefixType: route.IPv4Prefix,
|
||||||
|
Peer: peer2Key,
|
||||||
|
Description: "great",
|
||||||
|
Masquerade: true,
|
||||||
|
Metric: 3030,
|
||||||
|
Enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty Values",
|
||||||
|
existingRoute: existingRoute,
|
||||||
|
operations: []RouteUpdateOperation{
|
||||||
|
RouteUpdateOperation{
|
||||||
|
Type: UpdateRoutePeer,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errFunc: require.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Multiple Values",
|
||||||
|
existingRoute: existingRoute,
|
||||||
|
operations: []RouteUpdateOperation{
|
||||||
|
RouteUpdateOperation{
|
||||||
|
Type: UpdateRoutePeer,
|
||||||
|
Values: []string{peer2Key, peer1Key},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errFunc: require.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bad Prefix",
|
||||||
|
existingRoute: existingRoute,
|
||||||
|
operations: []RouteUpdateOperation{
|
||||||
|
RouteUpdateOperation{
|
||||||
|
Type: UpdateRoutePrefix,
|
||||||
|
Values: []string{"192.168.0.0/34"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errFunc: require.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bad Peer",
|
||||||
|
existingRoute: existingRoute,
|
||||||
|
operations: []RouteUpdateOperation{
|
||||||
|
RouteUpdateOperation{
|
||||||
|
Type: UpdateRoutePeer,
|
||||||
|
Values: []string{"non existing Peer"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errFunc: require.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty Peer",
|
||||||
|
existingRoute: existingRoute,
|
||||||
|
operations: []RouteUpdateOperation{
|
||||||
|
RouteUpdateOperation{
|
||||||
|
Type: UpdateRoutePeer,
|
||||||
|
Values: []string{""},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errFunc: require.NoError,
|
||||||
|
shouldCreate: true,
|
||||||
|
expectedRoute: &route.Route{
|
||||||
|
ID: routeID,
|
||||||
|
Prefix: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
|
PrefixType: route.IPv4Prefix,
|
||||||
|
Peer: "",
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid Metric",
|
||||||
|
existingRoute: existingRoute,
|
||||||
|
operations: []RouteUpdateOperation{
|
||||||
|
RouteUpdateOperation{
|
||||||
|
Type: UpdateRouteMetric,
|
||||||
|
Values: []string{"999999"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errFunc: require.Error,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid Boolean",
|
||||||
|
existingRoute: existingRoute,
|
||||||
|
operations: []RouteUpdateOperation{
|
||||||
|
RouteUpdateOperation{
|
||||||
|
Type: UpdateRouteMasquerade,
|
||||||
|
Values: []string{"yes"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
errFunc: require.Error,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
|
am, err := createRouterManager(t)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("failed to create account manager")
|
||||||
|
}
|
||||||
|
|
||||||
|
account, err := initTestRouteAccount(t, am)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("failed to init testing account")
|
||||||
|
}
|
||||||
|
|
||||||
|
account.Routes[testCase.existingRoute.ID] = testCase.existingRoute
|
||||||
|
|
||||||
|
err = am.Store.SaveAccount(account)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("account should be saved")
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedRoute, err := am.UpdateRoute(account.Id, testCase.existingRoute.ID, testCase.operations)
|
||||||
|
|
||||||
|
testCase.errFunc(t, err)
|
||||||
|
|
||||||
|
if !testCase.shouldCreate {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
testCase.expectedRoute.ID = updatedRoute.ID
|
||||||
|
|
||||||
|
if !testCase.expectedRoute.IsEqual(updatedRoute) {
|
||||||
|
t.Errorf("new route didn't match expected route:\nGot %#v\nExpected:%#v\n", updatedRoute, testCase.expectedRoute)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteRoute(t *testing.T) {
|
||||||
|
|
||||||
|
testingRoute := &route.Route{
|
||||||
|
ID: "testingRoute",
|
||||||
|
Prefix: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
|
PrefixType: route.IPv4Prefix,
|
||||||
|
Peer: peer1Key,
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
am, err := createRouterManager(t)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("failed to create account manager")
|
||||||
|
}
|
||||||
|
|
||||||
|
account, err := initTestRouteAccount(t, am)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("failed to init testing account")
|
||||||
|
}
|
||||||
|
|
||||||
|
account.Routes[testingRoute.ID] = testingRoute
|
||||||
|
|
||||||
|
err = am.Store.SaveAccount(account)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("failed to save account")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = am.DeleteRoute(account.Id, testingRoute.ID)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("deleting route failed with error: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
savedAccount, err := am.Store.GetAccount(account.Id)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("failed to retrieve saved account with error: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, found := savedAccount.Routes[testingRoute.ID]
|
||||||
|
if found {
|
||||||
|
t.Error("route shouldn't be found after delete")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetNetworkMap_RouteSync(t *testing.T) {
|
||||||
|
// no routes for peer in different groups
|
||||||
|
// no routes when route is deleted
|
||||||
|
|
||||||
|
baseRoute := &route.Route{
|
||||||
|
ID: "testingRoute",
|
||||||
|
Prefix: netip.MustParsePrefix("192.168.0.0/16"),
|
||||||
|
PrefixType: route.IPv4Prefix,
|
||||||
|
Peer: peer1Key,
|
||||||
|
Description: "super",
|
||||||
|
Masquerade: false,
|
||||||
|
Metric: 9999,
|
||||||
|
Enabled: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
am, err := createRouterManager(t)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("failed to create account manager")
|
||||||
|
}
|
||||||
|
|
||||||
|
account, err := initTestRouteAccount(t, am)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("failed to init testing account")
|
||||||
|
}
|
||||||
|
|
||||||
|
newAccountRoutes, err := am.GetNetworkMap(peer1Key)
|
||||||
|
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)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
noDisabledRoutes, err := am.GetNetworkMap(peer1Key)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, noDisabledRoutes.Routes, 0, "no routes for disabled routes")
|
||||||
|
|
||||||
|
enabledRoute := createdRoute.Copy()
|
||||||
|
enabledRoute.Enabled = true
|
||||||
|
|
||||||
|
err = am.SaveRoute(account.Id, enabledRoute)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
peer1Routes, err := am.GetNetworkMap(peer1Key)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, peer1Routes.Routes, 1, "we should receive one route for peer1")
|
||||||
|
require.True(t, enabledRoute.IsEqual(peer1Routes.Routes[0]), "received route should be equal")
|
||||||
|
|
||||||
|
peer2Routes, err := am.GetNetworkMap(peer2Key)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, peer2Routes.Routes, 1, "we should receive one route for peer2")
|
||||||
|
require.True(t, peer1Routes.Routes[0].IsEqual(peer2Routes.Routes[0]), "routes should be the same for peers in the same group")
|
||||||
|
|
||||||
|
newGroup := &Group{
|
||||||
|
ID: xid.New().String(),
|
||||||
|
Name: "peer1 group",
|
||||||
|
Peers: []string{peer1Key},
|
||||||
|
}
|
||||||
|
err = am.SaveGroup(account.Id, newGroup)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
rules, err := am.ListRules(account.Id)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
defaultRule := rules[0]
|
||||||
|
newRule := defaultRule.Copy()
|
||||||
|
newRule.ID = xid.New().String()
|
||||||
|
newRule.Name = "peer1 only"
|
||||||
|
newRule.Source = []string{newGroup.ID}
|
||||||
|
newRule.Destination = []string{newGroup.ID}
|
||||||
|
|
||||||
|
err = am.SaveRule(account.Id, newRule)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = am.DeleteRule(account.Id, defaultRule.ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
peer1GroupRoutes, err := am.GetNetworkMap(peer1Key)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, peer1GroupRoutes.Routes, 1, "we should receive one route for peer1")
|
||||||
|
|
||||||
|
peer2GroupRoutes, err := am.GetNetworkMap(peer2Key)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, peer2GroupRoutes.Routes, 0, "we should not receive routes for peer2")
|
||||||
|
|
||||||
|
err = am.DeleteRoute(account.Id, enabledRoute.ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
peer1DeletedRoute, err := am.GetNetworkMap(peer1Key)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, peer1DeletedRoute.Routes, 0, "we should receive one route for peer1")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func createRouterManager(t *testing.T) (*DefaultAccountManager, error) {
|
||||||
|
store, err := createRouterStore(t)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return BuildManager(store, NewPeersUpdateManager(), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createRouterStore(t *testing.T) (Store, error) {
|
||||||
|
dataDir := t.TempDir()
|
||||||
|
store, err := NewStore(dataDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return store, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*Account, error) {
|
||||||
|
peer1 := &Peer{
|
||||||
|
Key: peer1Key,
|
||||||
|
Name: "test-host1@netbird.io",
|
||||||
|
Meta: PeerSystemMeta{
|
||||||
|
Hostname: "test-host1@netbird.io",
|
||||||
|
GoOS: "linux",
|
||||||
|
Kernel: "Linux",
|
||||||
|
Core: "21.04",
|
||||||
|
Platform: "x86_64",
|
||||||
|
OS: "Ubuntu",
|
||||||
|
WtVersion: "development",
|
||||||
|
UIVersion: "development",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
peer2 := &Peer{
|
||||||
|
Key: peer2Key,
|
||||||
|
Name: "test-host2@netbird.io",
|
||||||
|
Meta: PeerSystemMeta{
|
||||||
|
Hostname: "test-host2@netbird.io",
|
||||||
|
GoOS: "linux",
|
||||||
|
Kernel: "Linux",
|
||||||
|
Core: "21.04",
|
||||||
|
Platform: "x86_64",
|
||||||
|
OS: "Ubuntu",
|
||||||
|
WtVersion: "development",
|
||||||
|
UIVersion: "development",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
accountID := "testingAcc"
|
||||||
|
userID := "testingUser"
|
||||||
|
domain := "example.com"
|
||||||
|
|
||||||
|
account := newAccountWithId(accountID, userID, domain)
|
||||||
|
err := am.Store.SaveAccount(account)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = am.AddPeer("", userID, peer1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, err = am.AddPeer("", userID, peer2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return account, nil
|
||||||
|
}
|
@ -1,5 +1,10 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/netbirdio/netbird/route"
|
||||||
|
"net/netip"
|
||||||
|
)
|
||||||
|
|
||||||
type Store interface {
|
type Store interface {
|
||||||
GetPeer(peerKey string) (*Peer, error)
|
GetPeer(peerKey string) (*Peer, error)
|
||||||
DeletePeer(accountId string, peerKey string) (*Peer, error)
|
DeletePeer(accountId string, peerKey string) (*Peer, error)
|
||||||
@ -14,4 +19,6 @@ type Store interface {
|
|||||||
GetAccountBySetupKey(setupKey string) (*Account, error)
|
GetAccountBySetupKey(setupKey string) (*Account, error)
|
||||||
GetAccountByPrivateDomain(domain string) (*Account, error)
|
GetAccountByPrivateDomain(domain string) (*Account, error)
|
||||||
SaveAccount(account *Account) error
|
SaveAccount(account *Account) error
|
||||||
|
GetPeerRoutes(peerKey string) ([]*route.Route, error)
|
||||||
|
GetRoutesByPrefix(accountID string, prefix netip.Prefix) ([]*route.Route, error)
|
||||||
}
|
}
|
||||||
|
119
route/route.go
Normal file
119
route/route.go
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
package route
|
||||||
|
|
||||||
|
import (
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
"net/netip"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
)
|
||||||
|
const (
|
||||||
|
// InvalidPrefixString invalid prefix type string
|
||||||
|
InvalidPrefixString = "Invalid"
|
||||||
|
// IPv4PrefixString IPv4 prefix type string
|
||||||
|
IPv4PrefixString = "IPv4"
|
||||||
|
// IPv6PrefixString IPv6 prefix type string
|
||||||
|
IPv6PrefixString = "IPv6"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// InvalidPrefix invalid prefix type
|
||||||
|
InvalidPrefix PrefixType = iota
|
||||||
|
// IPv4Prefix IPv4 prefix type
|
||||||
|
IPv4Prefix
|
||||||
|
// IPv6Prefix IPv6 prefix type
|
||||||
|
IPv6Prefix
|
||||||
|
)
|
||||||
|
|
||||||
|
// PrefixType route prefix type
|
||||||
|
type PrefixType int
|
||||||
|
|
||||||
|
// String returns prefix type string
|
||||||
|
func (p PrefixType) String() string {
|
||||||
|
switch p {
|
||||||
|
case IPv4Prefix:
|
||||||
|
return IPv4PrefixString
|
||||||
|
case IPv6Prefix:
|
||||||
|
return IPv6PrefixString
|
||||||
|
default:
|
||||||
|
return InvalidPrefixString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToPrefixType returns a prefix type
|
||||||
|
func ToPrefixType(prefix string) PrefixType {
|
||||||
|
switch prefix {
|
||||||
|
case IPv4PrefixString:
|
||||||
|
return IPv4Prefix
|
||||||
|
case IPv6PrefixString:
|
||||||
|
return IPv6Prefix
|
||||||
|
default:
|
||||||
|
return InvalidPrefix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Route represents a route
|
||||||
|
type Route struct {
|
||||||
|
Prefix netip.Prefix
|
||||||
|
ID string
|
||||||
|
Description string
|
||||||
|
Peer string
|
||||||
|
PrefixType PrefixType
|
||||||
|
Masquerade bool
|
||||||
|
Metric int
|
||||||
|
Enabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy copies a route object
|
||||||
|
func (r *Route) Copy() *Route {
|
||||||
|
return &Route{
|
||||||
|
ID: r.ID,
|
||||||
|
Description: r.Description,
|
||||||
|
Prefix: r.Prefix,
|
||||||
|
PrefixType: r.PrefixType,
|
||||||
|
Peer: r.Peer,
|
||||||
|
Metric: r.Metric,
|
||||||
|
Masquerade: r.Masquerade,
|
||||||
|
Enabled: r.Enabled,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEqual compares one route with the other
|
||||||
|
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.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)
|
||||||
|
if err != nil {
|
||||||
|
return InvalidPrefix, netip.Prefix{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
masked := prefix.Masked()
|
||||||
|
|
||||||
|
if !masked.IsValid() {
|
||||||
|
return InvalidPrefix, netip.Prefix{}, status.Errorf(codes.InvalidArgument, "invalid range %s", prefixString)
|
||||||
|
}
|
||||||
|
|
||||||
|
if masked.Addr().Is6() {
|
||||||
|
return IPv6Prefix, masked, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return IPv4Prefix, masked, nil
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user