mirror of
https://github.com/netbirdio/netbird.git
synced 2025-02-16 18:21:24 +01:00
Add client version to the client app and send it to the management service (#222)
* test: WIP mocking the grpc server for testing the sending of the client information * WIP: Test_SystemMetaDataFromClient with mocks, todo: * fix: failing meta data test * test: add system meta expectation in management client test * fix: removing deprecated register function, replacing with new one * fix: removing deprecated register function from mockclient interface impl * fix: fixing interface declaration * chore: remove unused commented code Co-authored-by: braginini <bangvalo@gmail.com>
This commit is contained in:
parent
3c959bb178
commit
b59fd50226
@ -4,19 +4,21 @@ import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/google/uuid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/wiretrustee/wiretrustee/client/internal"
|
||||
"github.com/wiretrustee/wiretrustee/client/system"
|
||||
mgm "github.com/wiretrustee/wiretrustee/management/client"
|
||||
mgmProto "github.com/wiretrustee/wiretrustee/management/proto"
|
||||
"github.com/wiretrustee/wiretrustee/util"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -143,7 +145,8 @@ func registerPeer(serverPublicKey wgtypes.Key, client *mgm.GrpcClient, setupKey
|
||||
}
|
||||
|
||||
log.Debugf("sending peer registration request to Management Service")
|
||||
loginResp, err := client.Register(serverPublicKey, validSetupKey.String())
|
||||
info := system.GetInfo()
|
||||
loginResp, err := client.Register(serverPublicKey, validSetupKey.String(), info)
|
||||
if err != nil {
|
||||
log.Errorf("failed registering peer %v", err)
|
||||
return nil, err
|
||||
|
@ -2,6 +2,8 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/kardianos/service"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@ -13,7 +15,6 @@ import (
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -186,7 +187,6 @@ func runClient() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// create start the Wiretrustee Engine that will connect to the Signal and Management streams and manage connections to remote peers.
|
||||
engine := internal.NewEngine(signalClient, mgmClient, engineConfig, cancel, ctx)
|
||||
err = engine.Start()
|
||||
if err != nil {
|
||||
|
@ -3,6 +3,11 @@ package internal
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pion/ice/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/wiretrustee/wiretrustee/client/internal/peer"
|
||||
@ -14,10 +19,6 @@ import (
|
||||
sProto "github.com/wiretrustee/wiretrustee/signal/proto"
|
||||
"github.com/wiretrustee/wiretrustee/util"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// PeerConnectionTimeoutMax is a timeout of an initial connection attempt to a remote peer.
|
||||
|
@ -3,7 +3,16 @@ package internal
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/wiretrustee/wiretrustee/client/system"
|
||||
mgmt "github.com/wiretrustee/wiretrustee/management/client"
|
||||
mgmtProto "github.com/wiretrustee/wiretrustee/management/proto"
|
||||
"github.com/wiretrustee/wiretrustee/management/server"
|
||||
@ -14,13 +23,6 @@ import (
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -382,7 +384,8 @@ func createEngine(ctx context.Context, cancel context.CancelFunc, setupKey strin
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := mgmtClient.Register(*publicKey, setupKey)
|
||||
info := system.GetInfo()
|
||||
resp, err := mgmtClient.Register(*publicKey, setupKey, info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
4
go.mod
4
go.mod
@ -30,6 +30,8 @@ require (
|
||||
require (
|
||||
github.com/cakturk/go-netstat v0.0.0-20200220111822-e5b49efee7a5
|
||||
github.com/magiconair/properties v1.8.5
|
||||
github.com/pion/logging v0.2.2
|
||||
github.com/pion/turn/v2 v2.0.5
|
||||
github.com/rs/xid v1.3.0
|
||||
github.com/stretchr/testify v1.7.0
|
||||
)
|
||||
@ -46,12 +48,10 @@ require (
|
||||
github.com/mdlayher/socket v0.0.0-20211102153432-57e3fa563ecb // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/pion/dtls/v2 v2.0.12 // indirect
|
||||
github.com/pion/logging v0.2.2 // indirect
|
||||
github.com/pion/mdns v0.0.5 // indirect
|
||||
github.com/pion/randutil v0.1.0 // indirect
|
||||
github.com/pion/stun v0.3.5 // indirect
|
||||
github.com/pion/transport v0.12.3 // indirect
|
||||
github.com/pion/turn/v2 v2.0.5 // indirect
|
||||
github.com/pion/udp v0.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect
|
||||
|
@ -1,15 +1,17 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/wiretrustee/wiretrustee/client/system"
|
||||
"github.com/wiretrustee/wiretrustee/management/proto"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
"io"
|
||||
)
|
||||
|
||||
type Client interface {
|
||||
io.Closer
|
||||
Sync(msgHandler func(msg *proto.SyncResponse) error) error
|
||||
GetServerPublicKey() (*wgtypes.Key, error)
|
||||
Register(serverKey wgtypes.Key, setupKey string) (*proto.LoginResponse, error)
|
||||
Register(serverKey wgtypes.Key, setupKey string, info *system.Info) (*proto.LoginResponse, error)
|
||||
Login(serverKey wgtypes.Key) (*proto.LoginResponse, error)
|
||||
}
|
||||
|
@ -2,7 +2,18 @@ package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/wiretrustee/wiretrustee/client/system"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/wiretrustee/wiretrustee/encryption"
|
||||
"github.com/wiretrustee/wiretrustee/management/proto"
|
||||
mgmtProto "github.com/wiretrustee/wiretrustee/management/proto"
|
||||
mgmt "github.com/wiretrustee/wiretrustee/management/server"
|
||||
"github.com/wiretrustee/wiretrustee/util"
|
||||
@ -10,14 +21,12 @@ import (
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"net"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var tested *GrpcClient
|
||||
var serverAddr string
|
||||
var mgmtMockServer *mgmt.ManagementServiceServerMock
|
||||
var serverKey wgtypes.Key
|
||||
|
||||
const ValidKey = "A2C8E62B-38F5-4553-B31E-DD66C696CEBB"
|
||||
|
||||
@ -78,6 +87,39 @@ func startManagement(config *mgmt.Config, t *testing.T) (*grpc.Server, net.Liste
|
||||
return s, lis
|
||||
}
|
||||
|
||||
func startMockManagement(t *testing.T) (*grpc.Server, net.Listener) {
|
||||
lis, err := net.Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := grpc.NewServer()
|
||||
|
||||
serverKey, err = wgtypes.GenerateKey()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mgmtMockServer = &mgmt.ManagementServiceServerMock{
|
||||
GetServerKeyFunc: func(context.Context, *proto.Empty) (*proto.ServerKeyResponse, error) {
|
||||
response := &proto.ServerKeyResponse{
|
||||
Key: serverKey.PublicKey().String(),
|
||||
}
|
||||
return response, nil
|
||||
},
|
||||
}
|
||||
|
||||
mgmtProto.RegisterManagementServiceServer(s, mgmtMockServer)
|
||||
go func() {
|
||||
if err := s.Serve(lis); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
return s, lis
|
||||
}
|
||||
|
||||
func TestClient_GetServerPublicKey(t *testing.T) {
|
||||
|
||||
key, err := tested.GetServerPublicKey()
|
||||
@ -109,7 +151,8 @@ func TestClient_LoginRegistered(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
resp, err := tested.Register(*key, ValidKey)
|
||||
info := system.GetInfo()
|
||||
resp, err := tested.Register(*key, ValidKey, info)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@ -125,7 +168,8 @@ func TestClient_Sync(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = tested.Register(*serverKey, ValidKey)
|
||||
info := system.GetInfo()
|
||||
_, err = tested.Register(*serverKey, ValidKey, info)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@ -139,7 +183,9 @@ func TestClient_Sync(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = remoteClient.Register(*serverKey, ValidKey)
|
||||
|
||||
info = system.GetInfo()
|
||||
_, err = remoteClient.Register(*serverKey, ValidKey, info)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -177,3 +223,82 @@ func TestClient_Sync(t *testing.T) {
|
||||
t.Error("timeout waiting for test to finish")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SystemMetaDataFromClient(t *testing.T) {
|
||||
_, lis := startMockManagement(t)
|
||||
|
||||
testKey, err := wgtypes.GenerateKey()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
serverAddr := lis.Addr().String()
|
||||
ctx := context.Background()
|
||||
|
||||
testClient, err := NewClient(ctx, serverAddr, testKey, false)
|
||||
if err != nil {
|
||||
log.Fatalf("error while creating testClient: %v", err)
|
||||
}
|
||||
|
||||
key, err := testClient.GetServerPublicKey()
|
||||
if err != nil {
|
||||
log.Fatalf("error while getting server public key from testclient, %v", err)
|
||||
}
|
||||
|
||||
var actualMeta *proto.PeerSystemMeta
|
||||
var actualValidKey string
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
|
||||
mgmtMockServer.LoginFunc =
|
||||
func(ctx context.Context, msg *proto.EncryptedMessage) (*proto.EncryptedMessage, error) {
|
||||
peerKey, err := wgtypes.ParseKey(msg.GetWgPubKey())
|
||||
if err != nil {
|
||||
log.Warnf("error while parsing peer's Wireguard public key %s on Sync request.", msg.WgPubKey)
|
||||
return nil, status.Errorf(codes.InvalidArgument, "provided wgPubKey %s is invalid", msg.WgPubKey)
|
||||
}
|
||||
|
||||
loginReq := &proto.LoginRequest{}
|
||||
err = encryption.DecryptMessage(peerKey, serverKey, msg.Body, loginReq)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
actualMeta = loginReq.GetMeta()
|
||||
actualValidKey = loginReq.GetSetupKey()
|
||||
wg.Done()
|
||||
|
||||
loginResp := &proto.LoginResponse{}
|
||||
encryptedResp, err := encryption.EncryptMessage(peerKey, serverKey, loginResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &mgmtProto.EncryptedMessage{
|
||||
WgPubKey: serverKey.PublicKey().String(),
|
||||
Body: encryptedResp,
|
||||
Version: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
info := system.GetInfo()
|
||||
_, err = testClient.Register(*key, ValidKey, info)
|
||||
if err != nil {
|
||||
t.Errorf("error while trying to register client: %v", err)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
expectedMeta := &proto.PeerSystemMeta{
|
||||
Hostname: info.Hostname,
|
||||
GoOS: info.GoOS,
|
||||
Kernel: info.Kernel,
|
||||
Core: info.OSVersion,
|
||||
Platform: info.Platform,
|
||||
OS: info.OS,
|
||||
WiretrusteeVersion: info.WiretrusteeVersion,
|
||||
}
|
||||
|
||||
assert.Equal(t, ValidKey, actualValidKey)
|
||||
assert.Equal(t, expectedMeta, actualMeta)
|
||||
}
|
||||
|
@ -233,18 +233,16 @@ func (c *GrpcClient) login(serverKey wgtypes.Key, req *proto.LoginRequest) (*pro
|
||||
// Register registers peer on Management Server. It actually calls a Login endpoint with a provided setup key
|
||||
// Takes care of encrypting and decrypting messages.
|
||||
// This method will also collect system info and send it with the request (e.g. hostname, os, etc)
|
||||
func (c *GrpcClient) Register(serverKey wgtypes.Key, setupKey string) (*proto.LoginResponse, error) {
|
||||
gi := system.GetInfo()
|
||||
func (c *GrpcClient) Register(serverKey wgtypes.Key, setupKey string, info *system.Info) (*proto.LoginResponse, error) {
|
||||
meta := &proto.PeerSystemMeta{
|
||||
Hostname: gi.Hostname,
|
||||
GoOS: gi.GoOS,
|
||||
OS: gi.OS,
|
||||
Core: gi.OSVersion,
|
||||
Platform: gi.Platform,
|
||||
Kernel: gi.Kernel,
|
||||
WiretrusteeVersion: gi.WiretrusteeVersion,
|
||||
Hostname: info.Hostname,
|
||||
GoOS: info.GoOS,
|
||||
OS: info.OS,
|
||||
Core: info.OSVersion,
|
||||
Platform: info.Platform,
|
||||
Kernel: info.Kernel,
|
||||
WiretrusteeVersion: info.WiretrusteeVersion,
|
||||
}
|
||||
log.Debugf("detected system %v", meta)
|
||||
return c.login(serverKey, &proto.LoginRequest{SetupKey: setupKey, Meta: meta})
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/wiretrustee/wiretrustee/client/system"
|
||||
"github.com/wiretrustee/wiretrustee/management/proto"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
@ -9,7 +10,7 @@ type MockClient struct {
|
||||
CloseFunc func() error
|
||||
SyncFunc func(msgHandler func(msg *proto.SyncResponse) error) error
|
||||
GetServerPublicKeyFunc func() (*wgtypes.Key, error)
|
||||
RegisterFunc func(serverKey wgtypes.Key, setupKey string) (*proto.LoginResponse, error)
|
||||
RegisterFunc func(serverKey wgtypes.Key, setupKey string, info *system.Info) (*proto.LoginResponse, error)
|
||||
LoginFunc func(serverKey wgtypes.Key) (*proto.LoginResponse, error)
|
||||
}
|
||||
|
||||
@ -34,11 +35,11 @@ func (m *MockClient) GetServerPublicKey() (*wgtypes.Key, error) {
|
||||
return m.GetServerPublicKeyFunc()
|
||||
}
|
||||
|
||||
func (m *MockClient) Register(serverKey wgtypes.Key, setupKey string) (*proto.LoginResponse, error) {
|
||||
func (m *MockClient) Register(serverKey wgtypes.Key, setupKey string, info *system.Info) (*proto.LoginResponse, error) {
|
||||
if m.RegisterFunc == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return m.RegisterFunc(serverKey, setupKey)
|
||||
return m.RegisterFunc(serverKey, setupKey, info)
|
||||
}
|
||||
|
||||
func (m *MockClient) Login(serverKey wgtypes.Key) (*proto.LoginResponse, error) {
|
||||
|
@ -9,11 +9,13 @@ package management;
|
||||
service ManagementService {
|
||||
|
||||
// Login logs in peer. In case server returns codes.PermissionDenied this endpoint can be used to register Peer providing LoginRequest.setupKey
|
||||
// Returns encrypted LoginResponse in EncryptedMessage.Body
|
||||
rpc Login(EncryptedMessage) returns (EncryptedMessage) {}
|
||||
|
||||
// Sync enables peer synchronization. Each peer that is connected to this stream will receive updates from the server.
|
||||
// For example, if a new peer has been added to an account all other connected peers will receive this peer's Wireguard public key as an update
|
||||
// The initial SyncResponse contains all of the available peers so the local state can be refreshed
|
||||
// Returns encrypted SyncResponse in EncryptedMessage.Body
|
||||
rpc Sync(EncryptedMessage) returns (stream EncryptedMessage) {}
|
||||
|
||||
// Exposes a Wireguard public key of the Management service.
|
||||
|
46
management/server/management_server_mock.go
Normal file
46
management/server/management_server_mock.go
Normal file
@ -0,0 +1,46 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/wiretrustee/wiretrustee/management/proto"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type ManagementServiceServerMock struct {
|
||||
proto.UnimplementedManagementServiceServer
|
||||
|
||||
LoginFunc func(context.Context, *proto.EncryptedMessage) (*proto.EncryptedMessage, error)
|
||||
SyncFunc func(*proto.EncryptedMessage, proto.ManagementService_SyncServer)
|
||||
GetServerKeyFunc func(context.Context, *proto.Empty) (*proto.ServerKeyResponse, error)
|
||||
IsHealthyFunc func(context.Context, *proto.Empty) (*proto.Empty, error)
|
||||
}
|
||||
|
||||
func (m ManagementServiceServerMock) Login(ctx context.Context, req *proto.EncryptedMessage) (*proto.EncryptedMessage, error) {
|
||||
if m.LoginFunc != nil {
|
||||
return m.LoginFunc(ctx, req)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Login not implemented")
|
||||
}
|
||||
|
||||
func (m ManagementServiceServerMock) Sync(msg *proto.EncryptedMessage, sync proto.ManagementService_SyncServer) error {
|
||||
if m.SyncFunc != nil {
|
||||
return m.Sync(msg, sync)
|
||||
}
|
||||
return status.Errorf(codes.Unimplemented, "method Sync not implemented")
|
||||
}
|
||||
|
||||
func (m ManagementServiceServerMock) GetServerKey(ctx context.Context, empty *proto.Empty) (*proto.ServerKeyResponse, error) {
|
||||
if m.GetServerKeyFunc != nil {
|
||||
return m.GetServerKeyFunc(ctx, empty)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetServerKey not implemented")
|
||||
}
|
||||
|
||||
func (m ManagementServiceServerMock) IsHealthy(ctx context.Context, empty *proto.Empty) (*proto.Empty, error) {
|
||||
if m.IsHealthyFunc != nil {
|
||||
return m.IsHealthyFunc(ctx, empty)
|
||||
}
|
||||
return nil, status.Errorf(codes.Unimplemented, "method IsHealthy not implemented")
|
||||
}
|
Loading…
Reference in New Issue
Block a user