Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change Management Sync protocol to support incremental (serial) network changes #191

Merged
merged 10 commits into from
Jan 16, 2022
2 changes: 1 addition & 1 deletion client/internal/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func GetConfig(managementURL string, configPath string, preSharedKey string) (*C

// generateKey generates a new Wireguard private key
func generateKey() string {
key, err := wgtypes.GenerateKey()
key, err := wgtypes.GeneratePrivateKey()
if err != nil {
panic(err)
}
Expand Down
411 changes: 277 additions & 134 deletions management/proto/management.pb.go

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions management/proto/management.proto
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,29 @@ message EncryptedMessage {

// encrypted message Body
bytes body = 2;
// Version of the Wiretrustee Management Service protocol
int32 version = 3;
}

message SyncRequest {}

// SyncResponse represents a state that should be applied to the local peer (e.g. Wiretrustee servers config as well as local peer and remote peers configs)
message SyncResponse {

// Global config
WiretrusteeConfig wiretrusteeConfig = 1;

// Deprecated. Use NetworkMap.PeerConfig
PeerConfig peerConfig = 2;

// Deprecated. Use NetworkMap.RemotePeerConfig
repeated RemotePeerConfig remotePeers = 3;

// Indicates whether remotePeers array is empty or not to bypass protobuf null and empty array equality.
// Deprecated. Use NetworkMap.remotePeersIsEmpty
bool remotePeersIsEmpty = 4;

NetworkMap NetworkMap = 5;
}

message LoginRequest {
Expand Down Expand Up @@ -76,6 +85,8 @@ message ServerKeyResponse {
string key = 1;
// Key expiration timestamp after which the key should be fetched again by the client
google.protobuf.Timestamp expiresAt = 2;
// Version of the Wiretrustee Management Service protocol
int32 version = 3;
}

message Empty {}
Expand Down Expand Up @@ -122,6 +133,24 @@ message PeerConfig {
string dns = 2;
}

// NetworkMap represents a network state of the peer with the corresponding configuration parameters to establish peer-to-peer connections
message NetworkMap {
// Serial is an ID of the network state to be used by clients to order updates.
// The larger the Serial the newer the configuration.
// E.g. the client app should keep track of this id locally and discard all the configurations with a lower value
uint64 Serial = 1;

// PeerConfig represents configuration of a peer
PeerConfig peerConfig = 2;

// RemotePeerConfig represents a list of remote peers that the receiver can connect to
repeated RemotePeerConfig remotePeers = 3;

// Indicates whether remotePeers array is empty or not to bypass protobuf null and empty array equality.
bool remotePeersIsEmpty = 4;

}

// RemotePeerConfig represents a configuration of a remote peer.
// The properties are used to configure Wireguard Peers sections
message RemotePeerConfig {
Expand Down
6 changes: 3 additions & 3 deletions management/server/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,15 +163,15 @@ func TestAccountManager_AddPeer(t *testing.T) {
return
}

key, err := wgtypes.GenerateKey()
key, err := wgtypes.GeneratePrivateKey()
if err != nil {
t.Fatal(err)
return
}
expectedPeerKey := key.PublicKey().String()
expectedPeerIP := "100.64.0.1"

peer, err := manager.AddPeer(setupKey.Key, Peer{
peer, err := manager.AddPeer(setupKey.Key, &Peer{
Key: expectedPeerKey,
Meta: PeerSystemMeta{},
Name: expectedPeerKey,
Expand Down Expand Up @@ -226,7 +226,7 @@ func TestAccountManager_DeletePeer(t *testing.T) {

peerKey := key.PublicKey().String()

_, err = manager.AddPeer(setupKey.Key, Peer{
_, err = manager.AddPeer(setupKey.Key, &Peer{
Key: peerKey,
Meta: PeerSystemMeta{},
Name: peerKey,
Expand Down
23 changes: 15 additions & 8 deletions management/server/grpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func (s *Server) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest) (*Pe
if meta == nil {
return nil, status.Errorf(codes.InvalidArgument, "peer meta data was not provided")
}
peer, err := s.accountManager.AddPeer(req.GetSetupKey(), Peer{
peer, err := s.accountManager.AddPeer(req.GetSetupKey(), &Peer{
Key: peerKey.String(),
Name: meta.GetHostname(),
Meta: PeerSystemMeta{
Expand All @@ -158,21 +158,22 @@ func (s *Server) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest) (*Pe
return nil, status.Errorf(codes.NotFound, "provided setup key doesn't exists")
}

peers, err := s.accountManager.GetPeersForAPeer(peer.Key)
//todo move to AccountManager the code below
networkMap, err := s.accountManager.GetNetworkMap(peer.Key)
if err != nil {
return nil, status.Error(codes.Internal, "internal server error")
}

// notify other peers of our registration
for _, remotePeer := range peers {
for _, remotePeer := range networkMap.Peers {
// exclude notified peer and add ourselves
peersToSend := []*Peer{peer}
for _, p := range peers {
for _, p := range networkMap.Peers {
if remotePeer.Key != p.Key {
peersToSend = append(peersToSend, p)
}
}
update := toSyncResponse(s.config, peer, peersToSend, nil)
update := toSyncResponse(s.config, peer, peersToSend, nil, networkMap.Network.Serial())
err = s.peersUpdateManager.SendUpdate(remotePeer.Key, &UpdateMessage{Update: update})
if err != nil {
// todo rethink if we should keep this return
Expand Down Expand Up @@ -317,7 +318,7 @@ func toRemotePeerConfig(peers []*Peer) []*proto.RemotePeerConfig {

}

func toSyncResponse(config *Config, peer *Peer, peers []*Peer, turnCredentials *TURNCredentials) *proto.SyncResponse {
func toSyncResponse(config *Config, peer *Peer, peers []*Peer, turnCredentials *TURNCredentials, serial uint64) *proto.SyncResponse {

wtConfig := toWiretrusteeConfig(config, turnCredentials)

Expand All @@ -330,6 +331,12 @@ func toSyncResponse(config *Config, peer *Peer, peers []*Peer, turnCredentials *
PeerConfig: pConfig,
RemotePeers: remotePeers,
RemotePeersIsEmpty: len(remotePeers) == 0,
NetworkMap: &proto.NetworkMap{
Serial: serial,
PeerConfig: pConfig,
RemotePeers: remotePeers,
RemotePeersIsEmpty: len(remotePeers) == 0,
},
}
}

Expand All @@ -341,7 +348,7 @@ func (s *Server) IsHealthy(ctx context.Context, req *proto.Empty) (*proto.Empty,
// sendInitialSync sends initial proto.SyncResponse to the peer requesting synchronization
func (s *Server) sendInitialSync(peerKey wgtypes.Key, peer *Peer, srv proto.ManagementService_SyncServer) error {

peers, err := s.accountManager.GetPeersForAPeer(peer.Key)
networkMap, err := s.accountManager.GetNetworkMap(peer.Key)
if err != nil {
log.Warnf("error getting a list of peers for a peer %s", peer.Key)
return err
Expand All @@ -355,7 +362,7 @@ func (s *Server) sendInitialSync(peerKey wgtypes.Key, peer *Peer, srv proto.Mana
} else {
turnCredentials = nil
}
plainResp := toSyncResponse(s.config, peer, peers, turnCredentials)
plainResp := toSyncResponse(s.config, peer, networkMap.Peers, turnCredentials, networkMap.Network.Serial())

encryptedResp, err := encryption.EncryptMessage(peerKey, s.wgKey, plainResp)
if err != nil {
Expand Down
Loading