Peer configuration management (#69)

* feature: add config properties to the SyncResponse of the management gRpc service

* fix: lint errors

* chore: modify management protocol according to the review notes

* fix: management proto fields sequence

* feature: add proper peer configuration to be synced

* chore: minor changes

* feature: finalize peer config management

* fix: lint errors

* feature: add management server config file

* refactor: extract hosts-config to a separate file

* refactor: review notes applied to correct file_store usage

* refactor: extract management service configuration to a file

* refactor: simplify management config
This commit is contained in:
Mikhail Bragin 2021-07-30 17:46:38 +02:00 committed by GitHub
parent c0c4c4a266
commit 2c2c1e19df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 690 additions and 237 deletions

View File

@ -16,9 +16,11 @@ docker run -d --name wiretrustee-management \
-p 33073:33073 \
-p 443:443 \
-v /var/lib/wiretrustee/:/var/lib/wiretrustee/ \
-v /etc/wiretrustee/:/etc/wiretrustee/ \
wiretrustee/wiretrustee:management-v0.0.8-SNAPSHOT-079d35e-amd64 \
--port 33073 \
--datadir /var/lib/wiretrustee/ \
--hosts-config /etc/wiretrustee/hosts-config.json \
--letsencrypt-domain <YOUR-DOMAIN> \
--log-level info
```
@ -91,13 +93,47 @@ Certificate:
docker run -d --name wiretrustee-management \
-p 33073:33073 \
-v /var/lib/wiretrustee/:/var/lib/wiretrustee/ \
-v /etc/wiretrustee/:/etc/wiretrustee/ \
wiretrustee/wiretrustee:management-v0.0.8-SNAPSHOT-079d35e-amd64 \
--port 33073 \
--datadir /var/lib/wiretrustee/ \
--hosts-config /etc/wiretrustee/hosts-config.json \
--letsencrypt-domain app.wiretrustee.com \
--log-level debug
```
### hosts-config.json file example:
```json
{
"Stuns": [
{
"Proto": 2,
"Host": "stun.wiretrustee.com",
"Port": 3468,
"Username": "",
"Password": null
}
],
"Turns": [
{
"Proto": 2,
"Host": "stun.wiretrustee.com",
"Port": 3468,
"Username": "some_user",
"Password": "c29tZV9wYXNzd29yZA=="
}
],
"Signal": {
"Proto": 2,
"Host": "signal.wiretrustee.com",
"Port": 10000,
"Username": "",
"Password": null
}
}
```
## For development purposes:
Install golang gRpc tools:

View File

@ -3,7 +3,8 @@ package cmd
import (
"flag"
"fmt"
server2 "github.com/wiretrustee/wiretrustee/management/server"
"github.com/wiretrustee/wiretrustee/management/server"
"github.com/wiretrustee/wiretrustee/util"
"net"
"os"
@ -21,6 +22,7 @@ import (
var (
mgmtPort int
mgmtDataDir string
mgmtConfig string
mgmtLetsencryptDomain string
kaep = keepalive.EnforcementPolicy{
@ -41,24 +43,29 @@ var (
Run: func(cmd *cobra.Command, args []string) {
flag.Parse()
if _, err := os.Stat(mgmtDataDir); os.IsNotExist(err) {
err = os.MkdirAll(mgmtDataDir, os.ModeDir)
config, err := loadConfig()
if err != nil {
log.Fatalf("failed reading provided config file: %s: %v", mgmtConfig, err)
}
if _, err = os.Stat(config.Datadir); os.IsNotExist(err) {
err = os.MkdirAll(config.Datadir, os.ModeDir)
if err != nil {
log.Fatalf("failed creating datadir: %s: %v", mgmtDataDir, err)
log.Fatalf("failed creating datadir: %s: %v", config.Datadir, err)
}
}
var opts []grpc.ServerOption
if mgmtLetsencryptDomain != "" {
transportCredentials := credentials.NewTLS(encryption.EnableLetsEncrypt(mgmtDataDir, mgmtLetsencryptDomain))
if config.LetsEncryptDomain != "" {
transportCredentials := credentials.NewTLS(encryption.EnableLetsEncrypt(config.Datadir, config.LetsEncryptDomain))
opts = append(opts, grpc.Creds(transportCredentials))
}
opts = append(opts, grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp))
grpcServer := grpc.NewServer(opts...)
server, err := server2.NewServer(mgmtDataDir)
server, err := server.NewServer(config)
if err != nil {
log.Fatalf("failed creating new server: %v", err)
}
@ -83,8 +90,28 @@ var (
}
)
func loadConfig() (*server.Config, error) {
config := &server.Config{}
_, err := util.ReadJson(mgmtConfig, config)
if err != nil {
return nil, err
}
if mgmtLetsencryptDomain != "" {
config.LetsEncryptDomain = mgmtLetsencryptDomain
}
if mgmtDataDir != "" {
config.Datadir = mgmtDataDir
}
return config, err
}
func init() {
mgmtCmd.Flags().IntVar(&mgmtPort, "port", 33073, "server port to listen on")
mgmtCmd.Flags().StringVar(&mgmtDataDir, "datadir", "/var/lib/wiretrustee/", "server data directory location")
mgmtCmd.Flags().StringVar(&mgmtConfig, "config", "/etc/wiretrustee/management.json", "Wiretrustee config file location. Config params specified via command line (e.g. datadir) have a precedence over configuration from this file")
mgmtCmd.Flags().StringVar(&mgmtLetsencryptDomain, "letsencrypt-domain", "", "a domain to issue Let's Encrypt certificate for. Enables TLS using Let's Encrypt. Will fetch and renew certificate, and run the server with TLS")
rootCmd.MarkFlagRequired("config") //nolint
}

View File

@ -24,22 +24,28 @@ const (
type HostConfig_Protocol int32
const (
HostConfig_PLAIN HostConfig_Protocol = 0
HostConfig_TLS HostConfig_Protocol = 1
HostConfig_DTLS HostConfig_Protocol = 2
HostConfig_UDP HostConfig_Protocol = 0
HostConfig_TCP HostConfig_Protocol = 1
HostConfig_HTTP HostConfig_Protocol = 2
HostConfig_HTTPS HostConfig_Protocol = 3
HostConfig_DTLS HostConfig_Protocol = 4
)
// Enum value maps for HostConfig_Protocol.
var (
HostConfig_Protocol_name = map[int32]string{
0: "PLAIN",
1: "TLS",
2: "DTLS",
0: "UDP",
1: "TCP",
2: "HTTP",
3: "HTTPS",
4: "DTLS",
}
HostConfig_Protocol_value = map[string]int32{
"PLAIN": 0,
"TLS": 1,
"DTLS": 2,
"UDP": 0,
"TCP": 1,
"HTTP": 2,
"HTTPS": 3,
"DTLS": 4,
}
)
@ -175,8 +181,6 @@ type SyncResponse struct {
WiretrusteeConfig *WiretrusteeConfig `protobuf:"bytes,1,opt,name=wiretrusteeConfig,proto3" json:"wiretrusteeConfig,omitempty"`
PeerConfig *PeerConfig `protobuf:"bytes,2,opt,name=peerConfig,proto3" json:"peerConfig,omitempty"`
RemotePeers []*RemotePeerConfig `protobuf:"bytes,3,rep,name=remotePeers,proto3" json:"remotePeers,omitempty"`
// Deprecated: used for compatibility
Peers []string `protobuf:"bytes,4,rep,name=peers,proto3" json:"peers,omitempty"`
}
func (x *SyncResponse) Reset() {
@ -232,13 +236,6 @@ func (x *SyncResponse) GetRemotePeers() []*RemotePeerConfig {
return nil
}
func (x *SyncResponse) GetPeers() []string {
if x != nil {
return x.Peers
}
return nil
}
type RegisterPeerRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -502,9 +499,9 @@ type HostConfig struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Host string `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"`
Port int32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
Protocol HostConfig_Protocol `protobuf:"varint,3,opt,name=protocol,proto3,enum=management.HostConfig_Protocol" json:"protocol,omitempty"`
// URI of the resource e.g. turns://stun.wiretrustee.com:4430 or signal.wiretrustee.com:10000
Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty"`
Protocol HostConfig_Protocol `protobuf:"varint,2,opt,name=protocol,proto3,enum=management.HostConfig_Protocol" json:"protocol,omitempty"`
}
func (x *HostConfig) Reset() {
@ -539,25 +536,18 @@ func (*HostConfig) Descriptor() ([]byte, []int) {
return file_management_proto_rawDescGZIP(), []int{8}
}
func (x *HostConfig) GetHost() string {
func (x *HostConfig) GetUri() string {
if x != nil {
return x.Host
return x.Uri
}
return ""
}
func (x *HostConfig) GetPort() int32 {
if x != nil {
return x.Port
}
return 0
}
func (x *HostConfig) GetProtocol() HostConfig_Protocol {
if x != nil {
return x.Protocol
}
return HostConfig_PLAIN
return HostConfig_UDP
}
// ProtectedHostConfig is similar to HostConfig but has additional user and password
@ -755,7 +745,7 @@ var file_management_proto_rawDesc = []byte{
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x67, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12,
0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62,
0x6f, 0x64, 0x79, 0x22, 0x0d, 0x0a, 0x0b, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x22, 0xe9, 0x01, 0x0a, 0x0c, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x73, 0x74, 0x22, 0xd3, 0x01, 0x0a, 0x0c, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x11, 0x77, 0x69, 0x72, 0x65, 0x74, 0x72, 0x75, 0x73, 0x74,
0x65, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d,
0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x57, 0x69, 0x72, 0x65,
@ -768,78 +758,76 @@ var file_management_proto_rawDesc = []byte{
0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e,
0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74,
0x65, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0b, 0x72, 0x65, 0x6d,
0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72,
0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x22, 0x43,
0x0a, 0x13, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x75, 0x70,
0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x74, 0x75, 0x70,
0x4b, 0x65, 0x79, 0x22, 0x16, 0x0a, 0x14, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50,
0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5f, 0x0a, 0x11, 0x53,
0x65, 0x72, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
0x65, 0x79, 0x12, 0x38, 0x0a, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
0x70, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x22, 0x07, 0x0a, 0x05,
0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0xa8, 0x01, 0x0a, 0x11, 0x57, 0x69, 0x72, 0x65, 0x74, 0x72,
0x75, 0x73, 0x74, 0x65, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2c, 0x0a, 0x05, 0x73,
0x74, 0x75, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e,
0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x73, 0x22, 0x43, 0x0a, 0x13, 0x52, 0x65, 0x67, 0x69,
0x73, 0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x74, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x22, 0x16, 0x0a,
0x14, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5f, 0x0a, 0x11, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4b,
0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x38, 0x0a, 0x09,
0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x65, 0x78, 0x70,
0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
0xa8, 0x01, 0x0a, 0x11, 0x57, 0x69, 0x72, 0x65, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2c, 0x0a, 0x05, 0x73, 0x74, 0x75, 0x6e, 0x73, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e,
0x74, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x05, 0x73, 0x74,
0x75, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x05, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e,
0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x52, 0x05, 0x74, 0x75, 0x72, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x06, 0x73, 0x69,
0x67, 0x6e, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e,
0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x52, 0x05, 0x73, 0x74, 0x75, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x05, 0x74, 0x75, 0x72,
0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67,
0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x48,
0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x05, 0x74, 0x75, 0x72, 0x6e, 0x73,
0x12, 0x2e, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
0x69, 0x67, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x22, 0x98, 0x01, 0x0a, 0x0a, 0x48,
0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x3b, 0x0a, 0x08, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e,
0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x22, 0x3b, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a,
0x03, 0x54, 0x43, 0x50, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x02,
0x12, 0x09, 0x0a, 0x05, 0x48, 0x54, 0x54, 0x50, 0x53, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x44,
0x54, 0x4c, 0x53, 0x10, 0x04, 0x22, 0x7d, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74,
0x65, 0x64, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x0a,
0x68, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x48, 0x6f,
0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c,
0x22, 0x9b, 0x01, 0x0a, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68,
0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28,
0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x3b, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x63, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x6d, 0x61, 0x6e, 0x61,
0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x22, 0x28, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x12, 0x09, 0x0a, 0x05, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x54,
0x4c, 0x53, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x54, 0x4c, 0x53, 0x10, 0x02, 0x22, 0x7d,
0x0a, 0x13, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x48, 0x6f, 0x73, 0x74, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x61,
0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x52, 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a,
0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65,
0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x38, 0x0a,
0x0a, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x61,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64,
0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x64, 0x6e, 0x73, 0x22, 0x4e, 0x0a, 0x10, 0x52, 0x65, 0x6d, 0x6f, 0x74,
0x65, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x77,
0x67, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77,
0x67, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77,
0x65, 0x64, 0x49, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x6c, 0x6c,
0x6f, 0x77, 0x65, 0x64, 0x49, 0x70, 0x73, 0x32, 0xa9, 0x02, 0x0a, 0x11, 0x4d, 0x61, 0x6e, 0x61,
0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x53, 0x0a,
0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x12, 0x1f, 0x2e,
0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73,
0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20,
0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x67, 0x69,
0x73, 0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 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, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73,
0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73,
0x77, 0x6f, 0x72, 0x64, 0x22, 0x38, 0x0a, 0x0a, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03,
0x64, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, 0x6e, 0x73, 0x22, 0x4e,
0x0a, 0x10, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x67, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x67, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x1e,
0x0a, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x49, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03,
0x28, 0x09, 0x52, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x49, 0x70, 0x73, 0x32, 0xa9,
0x02, 0x0a, 0x11, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x12, 0x53, 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
0x50, 0x65, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e,
0x74, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65,
0x6e, 0x74, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 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, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@ -41,9 +41,6 @@ message SyncResponse {
PeerConfig peerConfig = 2;
repeated RemotePeerConfig remotePeers = 3;
// Deprecated: used for compatibility
repeated string peers = 4;
}
message RegisterPeerRequest {
@ -78,14 +75,16 @@ message WiretrusteeConfig {
// HostConfig describes connection properties of some server (e.g. STUN, Signal, Management)
message HostConfig {
string host = 1;
int32 port = 2;
Protocol protocol = 3;
// URI of the resource e.g. turns://stun.wiretrustee.com:4430 or signal.wiretrustee.com:10000
string uri = 1;
Protocol protocol = 2;
enum Protocol {
PLAIN = 0;
TLS = 1;
DTLS = 2;
UDP = 0;
TCP = 1;
HTTP = 2;
HTTPS = 3;
DTLS = 4;
}
}
// ProtectedHostConfig is similar to HostConfig but has additional user and password

View File

@ -0,0 +1,119 @@
package server
import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"net"
"sync"
)
type AccountManager struct {
Store Store
// mutex to synchronise account operations (e.g. generating Peer IP address inside the Network)
mux sync.Mutex
}
// Account represents a unique account of the system
type Account struct {
Id string
SetupKeys map[string]*SetupKey
Network *Network
Peers []*Peer
}
// SetupKey represents a pre-authorized key used to register machines (peers)
// One key might have multiple machines
type SetupKey struct {
Key string
}
// Peer represents a machine connected to the network.
// The Peer is a Wireguard peer identified by a public key
type Peer struct {
// Wireguard public key
Key string
// A setup key this peer was registered with
SetupKey *SetupKey
// IP address of the Peer
IP net.IP
}
// NewManager creates a new AccountManager with a provided Store
func NewManager(store Store) *AccountManager {
return &AccountManager{
Store: store,
mux: sync.Mutex{},
}
}
// GetPeer returns a peer from a Store
func (manager *AccountManager) GetPeer(peerKey string) (*Peer, error) {
manager.mux.Lock()
defer manager.mux.Unlock()
peer, err := manager.Store.GetPeer(peerKey)
if err != nil {
return nil, status.Errorf(codes.NotFound, "provided peer key doesn't exists %s", peerKey)
}
return peer, nil
}
// GetPeersForAPeer returns a list of peers available for a given peer (key)
// Effectively all the peers of the original peer's account except for the peer itself
func (manager *AccountManager) GetPeersForAPeer(peerKey string) ([]*Peer, error) {
manager.mux.Lock()
defer manager.mux.Unlock()
account, err := manager.Store.GetPeerAccount(peerKey)
if err != nil {
return nil, status.Errorf(codes.Internal, "Invalid peer key %s", peerKey)
}
var res []*Peer
for _, peer := range account.Peers {
if peer.Key != peerKey {
res = append(res, peer)
}
}
return res, nil
}
// AddPeer adds a new peer to the Store.
// Each Account has a list of pre-authorised SetupKey and if no Account has a given key err wit ha code codes.Unauthenticated
// will be returned, meaning the key is invalid
// Each new Peer will be assigned a new next net.IP from the Account.Network and Account.Network.LastIP will be updated (IP's are not reused).
func (manager *AccountManager) AddPeer(setupKey string, peerKey string) (*Peer, error) {
manager.mux.Lock()
defer manager.mux.Unlock()
account, err := manager.Store.GetAccountBySetupKey(setupKey)
if err != nil {
//todo
return nil, err
}
var takenIps []net.IP
for _, peer := range account.Peers {
takenIps = append(takenIps, peer.IP)
}
network := account.Network
nextIp, _ := AllocatePeerIP(network.Net, takenIps)
newPeer := &Peer{
Key: peerKey,
SetupKey: &SetupKey{Key: setupKey},
IP: nextIp,
}
account.Peers = append(account.Peers, newPeer)
err = manager.Store.SaveAccount(account)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed adding peer")
}
return newPeer, nil
}

View File

@ -0,0 +1,30 @@
package server
type Protocol string
const (
UDP Protocol = "udp"
DTLS Protocol = "dtls"
TCP Protocol = "tcp"
HTTP Protocol = "http"
HTTPS Protocol = "https"
)
// Config of the Management service
type Config struct {
Stuns []*Host
Turns []*Host
Signal *Host
Datadir string
LetsEncryptDomain string
}
// Host represents a Wiretrustee host (e.g. STUN, TURN, Signal)
type Host struct {
Proto Protocol
// URI e.g. turns://stun.wiretrustee.com:4430 or signal.wiretrustee.com:10000
URI string
Username string
Password []byte
}

View File

@ -1,4 +1,4 @@
package store
package server
import (
"os"
@ -26,6 +26,9 @@ type FileStore struct {
storeFile string `json:"-"`
}
type StoredAccount struct {
}
// NewStore restores a store from the file located in the datadir
func NewStore(dataDir string) (*FileStore, error) {
return restore(filepath.Join(dataDir, storeFileName))
@ -59,15 +62,13 @@ func restore(file string) (*FileStore, error) {
store := read.(*FileStore)
store.storeFile = file
store.SetupKeyId2AccountId = make(map[string]string)
store.PeerKeyId2AccountId = make(map[string]string)
for accountId, account := range store.Accounts {
for setupKeyId := range account.SetupKeys {
store.SetupKeyId2AccountId[strings.ToLower(setupKeyId)] = accountId
}
}
store.PeerKeyId2AccountId = make(map[string]string)
for accountId, account := range store.Accounts {
for peerId := range account.Peers {
store.PeerKeyId2AccountId[strings.ToLower(peerId)] = accountId
for _, peer := range account.Peers {
store.PeerKeyId2AccountId[strings.ToLower(peer.Key)] = accountId
}
}
@ -80,47 +81,32 @@ func (s *FileStore) persist(file string) error {
return util.WriteJson(file, s)
}
// PeerExists checks whether peer exists or not
func (s *FileStore) PeerExists(peerKey string) bool {
// GetPeer returns a peer from a Store
func (s *FileStore) GetPeer(peerKey string) (*Peer, error) {
s.mux.Lock()
defer s.mux.Unlock()
_, accountIdFound := s.PeerKeyId2AccountId[peerKey]
return accountIdFound
}
// AddPeer adds peer to the store and associates it with a Account and a SetupKey. Returns related Account
// Each Account has a list of pre-authorised SetupKey and if no Account has a given key err will be returned, meaning the key is invalid
func (s *FileStore) AddPeer(setupKey string, peerKey string) error {
s.mux.Lock()
defer s.mux.Unlock()
accountId, accountIdFound := s.SetupKeyId2AccountId[strings.ToLower(setupKey)]
accountId, accountIdFound := s.PeerKeyId2AccountId[peerKey]
if !accountIdFound {
return status.Errorf(codes.NotFound, "Provided setup key doesn't exists")
return nil, status.Errorf(codes.Internal, "account not found")
}
account, accountFound := s.Accounts[accountId]
if !accountFound {
return status.Errorf(codes.Internal, "Invalid setup key")
}
key, setupKeyFound := account.SetupKeys[strings.ToLower(setupKey)]
if !setupKeyFound {
return status.Errorf(codes.Internal, "Invalid setup key")
}
account.Peers[peerKey] = &Peer{Key: peerKey, SetupKey: key}
s.PeerKeyId2AccountId[peerKey] = accountId
err := s.persist(s.storeFile)
account, err := s.GetAccount(accountId)
if err != nil {
return err
return nil, err
}
return nil
for _, peer := range account.Peers {
if peer.Key == peerKey {
return peer, nil
}
}
return nil, status.Errorf(codes.NotFound, "peer not found")
}
// AddAccount adds new account to the store.
func (s *FileStore) AddAccount(account *Account) error {
// SaveAccount updates an existing account or adds a new one
func (s *FileStore) SaveAccount(account *Account) error {
s.mux.Lock()
defer s.mux.Unlock()
@ -133,6 +119,10 @@ func (s *FileStore) AddAccount(account *Account) error {
s.SetupKeyId2AccountId[strings.ToLower(keyId)] = account.Id
}
for _, peer := range account.Peers {
s.PeerKeyId2AccountId[peer.Key] = account.Id
}
err := s.persist(s.storeFile)
if err != nil {
return err
@ -141,9 +131,32 @@ func (s *FileStore) AddAccount(account *Account) error {
return nil
}
// GetPeersForAPeer returns a list of peers available for a given peer (key)
// Effectively all the peers of the original peer's account if any
func (s *FileStore) GetPeersForAPeer(peerKey string) ([]string, error) {
func (s *FileStore) GetAccountBySetupKey(setupKey string) (*Account, error) {
accountId, accountIdFound := s.SetupKeyId2AccountId[strings.ToLower(setupKey)]
if !accountIdFound {
return nil, status.Errorf(codes.NotFound, "provided setup key doesn't exists")
}
account, err := s.GetAccount(accountId)
if err != nil {
return nil, err
}
return account, nil
}
func (s *FileStore) GetAccount(accountId string) (*Account, error) {
account, accountFound := s.Accounts[accountId]
if !accountFound {
return nil, status.Errorf(codes.Internal, "account not found")
}
return account, nil
}
func (s *FileStore) GetPeerAccount(peerKey string) (*Account, error) {
s.mux.Lock()
defer s.mux.Unlock()
@ -152,16 +165,5 @@ func (s *FileStore) GetPeersForAPeer(peerKey string) ([]string, error) {
return nil, status.Errorf(codes.NotFound, "Provided peer key doesn't exists %s", peerKey)
}
account, accountFound := s.Accounts[accountId]
if !accountFound {
return nil, status.Errorf(codes.Internal, "Invalid peer key %s", peerKey)
}
peers := make([]string, 0, len(account.Peers))
for p := range account.Peers {
if p != peerKey {
peers = append(peers, p)
}
}
return peers, nil
return s.GetAccount(accountId)
}

View File

@ -2,7 +2,7 @@ package server_test
import (
"context"
server2 "github.com/wiretrustee/wiretrustee/management/server"
server "github.com/wiretrustee/wiretrustee/management/server"
"io/ioutil"
"math/rand"
"net"
@ -33,7 +33,7 @@ var _ = Describe("Management service", func() {
var (
addr string
server *grpc.Server
s *grpc.Server
dataDir string
client mgmtProto.ManagementServiceClient
serverPubKey wgtypes.Key
@ -50,11 +50,17 @@ var _ = Describe("Management service", func() {
err = util.CopyFileContents("testdata/store.json", filepath.Join(dataDir, "store.json"))
Expect(err).NotTo(HaveOccurred())
var listener net.Listener
server, listener = startServer(dataDir)
config := &server.Config{}
_, err = util.ReadJson("testdata/management.json", config)
Expect(err).NotTo(HaveOccurred())
config.Datadir = dataDir
s, listener = startServer(config)
addr = listener.Addr().String()
client, conn = createRawClient(addr)
// server public key
// s public key
resp, err := client.GetServerKey(context.TODO(), &mgmtProto.Empty{})
Expect(err).NotTo(HaveOccurred())
serverPubKey, err = wgtypes.ParseKey(resp.Key)
@ -63,7 +69,7 @@ var _ = Describe("Management service", func() {
})
AfterEach(func() {
server.Stop()
s.Stop()
err := conn.Close()
Expect(err).NotTo(HaveOccurred())
err = os.RemoveAll(dataDir)
@ -82,6 +88,54 @@ var _ = Describe("Management service", func() {
Context("when calling Sync endpoint", func() {
Context("when there is a new peer registered", func() {
Specify("a proper configuration is returned", func() {
key, _ := wgtypes.GenerateKey()
registerPeerWithValidSetupKey(key, client)
encryptedBytes, err := encryption.EncryptMessage(serverPubKey, key, &mgmtProto.SyncRequest{})
Expect(err).NotTo(HaveOccurred())
sync, err := client.Sync(context.TODO(), &mgmtProto.EncryptedMessage{
WgPubKey: key.PublicKey().String(),
Body: encryptedBytes,
})
Expect(err).NotTo(HaveOccurred())
encryptedResponse := &mgmtProto.EncryptedMessage{}
err = sync.RecvMsg(encryptedResponse)
Expect(err).NotTo(HaveOccurred())
resp := &mgmtProto.SyncResponse{}
err = encryption.DecryptMessage(serverPubKey, key, encryptedResponse.Body, resp)
Expect(err).NotTo(HaveOccurred())
Expect(resp.PeerConfig.Address).To(BeEquivalentTo("100.64.0.1"))
expectedSignalConfig := &mgmtProto.HostConfig{
Uri: "signal.wiretrustee.com:10000",
Protocol: mgmtProto.HostConfig_HTTP,
}
expectedStunsConfig := &mgmtProto.HostConfig{
Uri: "stun:stun.wiretrustee.com:3468",
Protocol: mgmtProto.HostConfig_UDP,
}
expectedTurnsConfig := &mgmtProto.ProtectedHostConfig{
HostConfig: &mgmtProto.HostConfig{
Uri: "turn:stun.wiretrustee.com:3468",
Protocol: mgmtProto.HostConfig_UDP,
},
User: "some_user",
Password: "some_password",
}
Expect(resp.WiretrusteeConfig.Signal).To(BeEquivalentTo(expectedSignalConfig))
Expect(resp.WiretrusteeConfig.Stuns).To(ConsistOf(expectedStunsConfig))
Expect(resp.WiretrusteeConfig.Turns).To(ConsistOf(expectedTurnsConfig))
})
})
Context("when there are 3 peers registered under one account", func() {
Specify("a list containing other 2 peers is returned", func() {
key, _ := wgtypes.GenerateKey()
@ -112,8 +166,9 @@ var _ = Describe("Management service", func() {
err = pb.Unmarshal(decryptedBytes, resp)
Expect(err).NotTo(HaveOccurred())
Expect(resp.GetPeers()).To(HaveLen(2))
Expect(resp.GetPeers()).To(ContainElements(key1.PublicKey().String(), key2.PublicKey().String()))
Expect(resp.GetRemotePeers()).To(HaveLen(2))
peers := []string{resp.GetRemotePeers()[0].WgPubKey, resp.GetRemotePeers()[1].WgPubKey}
Expect(peers).To(ContainElements(key1.PublicKey().String(), key2.PublicKey().String()))
})
})
@ -143,7 +198,7 @@ var _ = Describe("Management service", func() {
Expect(err).NotTo(HaveOccurred())
resp := &mgmtProto.SyncResponse{}
err = pb.Unmarshal(decryptedBytes, resp)
Expect(resp.GetPeers()).To(HaveLen(0))
Expect(resp.GetRemotePeers()).To(HaveLen(0))
wg := sync2.WaitGroup{}
wg.Add(1)
@ -167,8 +222,8 @@ var _ = Describe("Management service", func() {
wg.Wait()
Expect(err).NotTo(HaveOccurred())
Expect(resp.GetPeers()).To(ContainElements(key1.PublicKey().String()))
Expect(resp.GetPeers()).To(HaveLen(1))
Expect(resp.GetRemotePeers()).To(HaveLen(1))
Expect(resp.GetRemotePeers()[0].WgPubKey).To(BeEquivalentTo(key1.PublicKey().String()))
})
})
})
@ -291,6 +346,52 @@ var _ = Describe("Management service", func() {
})
})
})
Context("when there are peers registered under one account concurrently", func() {
Specify("then there are no duplicate IPs", func() {
initialPeers := 30
ipChannel := make(chan string, 20)
for i := 0; i < initialPeers; i++ {
go func() {
key, _ := wgtypes.GenerateKey()
registerPeerWithValidSetupKey(key, client)
encryptedBytes, err := encryption.EncryptMessage(serverPubKey, key, &mgmtProto.SyncRequest{})
Expect(err).NotTo(HaveOccurred())
// open stream
sync, err := client.Sync(context.TODO(), &mgmtProto.EncryptedMessage{
WgPubKey: key.PublicKey().String(),
Body: encryptedBytes,
})
Expect(err).NotTo(HaveOccurred())
encryptedResponse := &mgmtProto.EncryptedMessage{}
err = sync.RecvMsg(encryptedResponse)
Expect(err).NotTo(HaveOccurred())
resp := &mgmtProto.SyncResponse{}
err = encryption.DecryptMessage(serverPubKey, key, encryptedResponse.Body, resp)
Expect(err).NotTo(HaveOccurred())
ipChannel <- resp.GetPeerConfig().Address
}()
}
ips := make(map[string]struct{})
for ip := range ipChannel {
if _, ok := ips[ip]; ok {
Fail("found duplicate IP: " + ip)
}
ips[ip] = struct{}{}
if len(ips) == initialPeers {
break
}
}
close(ipChannel)
})
})
})
func registerPeerWithValidSetupKey(key wgtypes.Key, client mgmtProto.ManagementServiceClient) *mgmtProto.RegisterPeerResponse {
@ -320,13 +421,13 @@ func createRawClient(addr string) (mgmtProto.ManagementServiceClient, *grpc.Clie
return mgmtProto.NewManagementServiceClient(conn), conn
}
func startServer(dataDir string) (*grpc.Server, net.Listener) {
func startServer(config *server.Config) (*grpc.Server, net.Listener) {
lis, err := net.Listen("tcp", ":0")
Expect(err).NotTo(HaveOccurred())
s := grpc.NewServer()
server, err := server2.NewServer(dataDir)
mgmtServer, err := server.NewServer(config)
Expect(err).NotTo(HaveOccurred())
mgmtProto.RegisterManagementServiceServer(s, server)
mgmtProto.RegisterManagementServiceServer(s, mgmtServer)
go func() {
if err := s.Serve(lis); err != nil {
Expect(err).NotTo(HaveOccurred())

View File

@ -0,0 +1,69 @@
package server
import (
"encoding/binary"
"fmt"
"net"
)
var (
upperIPv4 = []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 255, 255, 255, 255}
upperIPv6 = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
)
type Network struct {
Id string
Net net.IPNet
Dns string
}
// AllocatePeerIP pics an available IP from an net.IPNet.
// This method considers already taken IPs and reuses IPs if there are gaps in takenIps
// E.g. if ipNet=100.30.0.0/16 and takenIps=[100.30.0.1, 100.30.0.5] then the result would be 100.30.0.2
func AllocatePeerIP(ipNet net.IPNet, takenIps []net.IP) (net.IP, error) {
takenIpMap := make(map[string]net.IP)
takenIpMap[ipNet.IP.String()] = ipNet.IP
for _, ip := range takenIps {
takenIpMap[ip.String()] = ip
}
for ip := ipNet.IP.Mask(ipNet.Mask); ipNet.Contains(ip); ip = GetNextIP(ip) {
if _, ok := takenIpMap[ip.String()]; !ok {
return ip, nil
}
}
return nil, fmt.Errorf("failed allocating new IP for the ipNet %s and takenIps %s", ipNet.String(), takenIps)
}
// GetNextIP returns the next IP from the given IP address. If the given IP is
// the last IP of a v4 or v6 range, the same IP is returned.
// Credits to Cilium team.
// Copyright 2017-2020 Authors of Cilium
func GetNextIP(ip net.IP) net.IP {
if ip.Equal(upperIPv4) || ip.Equal(upperIPv6) {
return ip
}
nextIP := make(net.IP, len(ip))
switch len(ip) {
case net.IPv4len:
ipU32 := binary.BigEndian.Uint32(ip)
ipU32++
binary.BigEndian.PutUint32(nextIP, ipU32)
return nextIP
case net.IPv6len:
ipU64 := binary.BigEndian.Uint64(ip[net.IPv6len/2:])
ipU64++
binary.BigEndian.PutUint64(nextIP[net.IPv6len/2:], ipU64)
if ipU64 == 0 {
ipU64 = binary.BigEndian.Uint64(ip[:net.IPv6len/2])
ipU64++
binary.BigEndian.PutUint64(nextIP[:net.IPv6len/2], ipU64)
} else {
copy(nextIP[:net.IPv6len/2], ip[:net.IPv6len/2])
}
return nextIP
default:
return ip
}
}

View File

@ -2,7 +2,7 @@ package server
import (
"context"
"github.com/wiretrustee/wiretrustee/management/store"
"fmt"
"sync"
"time"
@ -17,33 +17,38 @@ import (
// Server an instance of a Management server
type Server struct {
Store *store.FileStore
wgKey wgtypes.Key
accountManager *AccountManager
wgKey wgtypes.Key
proto.UnimplementedManagementServiceServer
peerChannels map[string]chan *UpdateChannelMessage
channelsMux *sync.Mutex
config *Config
}
// AllowedIPsFormat generates Wireguard AllowedIPs format (e.g. 100.30.30.1/32)
const AllowedIPsFormat = "%s/32"
type UpdateChannelMessage struct {
Update *proto.SyncResponse
}
// NewServer creates a new Management server
func NewServer(dataDir string) (*Server, error) {
func NewServer(config *Config) (*Server, error) {
key, err := wgtypes.GeneratePrivateKey()
if err != nil {
return nil, err
}
store, err := store.NewStore(dataDir)
store, err := NewStore(config.Datadir)
if err != nil {
return nil, err
}
return &Server{
Store: store,
wgKey: key,
// peerKey -> event channel
peerChannels: make(map[string]chan *UpdateChannelMessage),
channelsMux: &sync.Mutex{},
peerChannels: make(map[string]chan *UpdateChannelMessage),
channelsMux: &sync.Mutex{},
accountManager: NewManager(store),
config: config,
}, nil
}
@ -73,8 +78,8 @@ func (s *Server) Sync(req *proto.EncryptedMessage, srv proto.ManagementService_S
return status.Errorf(codes.InvalidArgument, "provided wgPubKey %s is invalid", peerKey.String())
}
exists := s.Store.PeerExists(peerKey.String())
if !exists {
peer, err := s.accountManager.GetPeer(peerKey.String())
if err != nil {
return status.Errorf(codes.Unauthenticated, "provided peer with the key wgPubKey %s is not registered", peerKey.String())
}
@ -84,7 +89,7 @@ func (s *Server) Sync(req *proto.EncryptedMessage, srv proto.ManagementService_S
return status.Errorf(codes.InvalidArgument, "invalid request message")
}
err = s.sendInitialSync(peerKey, srv)
err = s.sendInitialSync(peerKey, peer, srv)
if err != nil {
return err
}
@ -132,28 +137,28 @@ func (s *Server) RegisterPeer(ctx context.Context, req *proto.RegisterPeerReques
s.channelsMux.Lock()
defer s.channelsMux.Unlock()
err := s.Store.AddPeer(req.SetupKey, req.Key)
peer, err := s.accountManager.AddPeer(req.SetupKey, req.Key)
if err != nil {
return &proto.RegisterPeerResponse{}, status.Errorf(codes.NotFound, "provided setup key doesn't exists")
}
peers, err := s.Store.GetPeersForAPeer(req.Key)
peers, err := s.accountManager.GetPeersForAPeer(peer.Key)
if err != nil {
//todo return a proper error
return nil, err
}
// notify other peers of our registration
for _, peer := range peers {
if channel, ok := s.peerChannels[peer]; ok {
for _, remotePeer := range peers {
if channel, ok := s.peerChannels[remotePeer.Key]; ok {
// exclude notified peer and add ourselves
peersToSend := []string{req.Key}
peersToSend := []*Peer{peer}
for _, p := range peers {
if peer != p {
if remotePeer.Key != p.Key {
peersToSend = append(peersToSend, p)
}
}
update := &proto.SyncResponse{Peers: peersToSend}
update := toSyncResponse(s.config, peer, peersToSend)
channel <- &UpdateChannelMessage{Update: update}
}
}
@ -161,6 +166,73 @@ func (s *Server) RegisterPeer(ctx context.Context, req *proto.RegisterPeerReques
return &proto.RegisterPeerResponse{}, nil
}
func toResponseProto(configProto Protocol) proto.HostConfig_Protocol {
switch configProto {
case UDP:
return proto.HostConfig_UDP
case DTLS:
return proto.HostConfig_DTLS
case HTTP:
return proto.HostConfig_HTTP
case HTTPS:
return proto.HostConfig_HTTPS
case TCP:
return proto.HostConfig_TCP
default:
//mbragin: todo something better?
panic(fmt.Errorf("unexpected config protocol type %v", configProto))
}
}
func toSyncResponse(config *Config, peer *Peer, peers []*Peer) *proto.SyncResponse {
var stuns []*proto.HostConfig
for _, stun := range config.Stuns {
stuns = append(stuns, &proto.HostConfig{
Uri: stun.URI,
Protocol: toResponseProto(stun.Proto),
})
}
var turns []*proto.ProtectedHostConfig
for _, turn := range config.Turns {
turns = append(turns, &proto.ProtectedHostConfig{
HostConfig: &proto.HostConfig{
Uri: turn.URI,
Protocol: toResponseProto(turn.Proto),
},
User: turn.Username,
Password: string(turn.Password),
})
}
wtConfig := &proto.WiretrusteeConfig{
Stuns: stuns,
Turns: turns,
Signal: &proto.HostConfig{
Uri: config.Signal.URI,
Protocol: toResponseProto(config.Signal.Proto),
},
}
pConfig := &proto.PeerConfig{
Address: peer.IP.String(),
}
remotePeers := make([]*proto.RemotePeerConfig, 0, len(peers))
for _, rPeer := range peers {
remotePeers = append(remotePeers, &proto.RemotePeerConfig{
WgPubKey: rPeer.Key,
AllowedIps: []string{fmt.Sprintf(AllowedIPsFormat, rPeer.IP)}, //todo /32
})
}
return &proto.SyncResponse{
WiretrusteeConfig: wtConfig,
PeerConfig: pConfig,
RemotePeers: remotePeers,
}
}
// IsHealthy indicates whether the service is healthy
func (s *Server) IsHealthy(ctx context.Context, req *proto.Empty) (*proto.Empty, error) {
return &proto.Empty{}, nil
@ -195,16 +267,14 @@ func (s *Server) closeUpdatesChannel(peerKey string) {
}
// sendInitialSync sends initial proto.SyncResponse to the peer requesting synchronization
func (s *Server) sendInitialSync(peerKey wgtypes.Key, srv proto.ManagementService_SyncServer) error {
func (s *Server) sendInitialSync(peerKey wgtypes.Key, peer *Peer, srv proto.ManagementService_SyncServer) error {
peers, err := s.Store.GetPeersForAPeer(peerKey.String())
peers, err := s.accountManager.GetPeersForAPeer(peer.Key)
if err != nil {
log.Warnf("error getting a list of peers for a peer %s", peerKey.String())
log.Warnf("error getting a list of peers for a peer %s", peer.Key)
return err
}
plainResp := &proto.SyncResponse{
Peers: peers,
}
plainResp := toSyncResponse(s.config, peer, peers)
encryptedResp, err := encryption.EncryptMessage(peerKey, s.wgKey, plainResp)
if err != nil {

View File

@ -0,0 +1,9 @@
package server
type Store interface {
GetPeer(peerId string) (*Peer, error)
GetAccount(accountId string) (*Account, error)
GetPeerAccount(peerId string) (*Account, error)
GetAccountBySetupKey(setupKey string) (*Account, error)
SaveAccount(account *Account) error
}

View File

@ -0,0 +1,25 @@
{
"Stuns": [
{
"Proto": "udp",
"URI": "stun:stun.wiretrustee.com:3468",
"Username": "",
"Password": null
}
],
"Turns": [
{
"Proto": "udp",
"URI": "turn:stun.wiretrustee.com:3468",
"Username": "some_user",
"Password": "c29tZV9wYXNzd29yZA=="
}
],
"Signal": {
"Proto": "http",
"URI": "signal.wiretrustee.com:10000",
"Username": "",
"Password": null
},
"DataDir": ""
}

View File

@ -7,7 +7,14 @@
"Key": "a2c8e62b-38f5-4553-b31e-dd66c696cebb"
}
},
"Peers": {}
"Network": {
"Id": "af1c8024-ha40-4ce2-9418-34653101fc3c",
"Net": {
"IP": "100.64.0.0",
"Mask": "/8AAAA=="
},
"Dns": null
}
}
}
}

View File

@ -1,29 +0,0 @@
package store
// Account represents a unique account of the system
type Account struct {
Id string
SetupKeys map[string]*SetupKey
Peers map[string]*Peer
}
// SetupKey represents a pre-authorized key used to register machines (peers)
// One key might have multiple machines
type SetupKey struct {
Key string
}
// Peer represents a machine connected to the network.
// The Peer is a Wireguard peer identified by a public key
type Peer struct {
// Wireguard public key
Key string
// A setup key this peer was registered with
SetupKey *SetupKey
}
type Store interface {
PeerExists(peerKey string) bool
AddPeer(setupKey string, peerKey string) error
GetPeersForAPeer(peerKey string) ([]string, error)
}