diff --git a/.github/workflows/golang-test.yml b/.github/workflows/golang-test.yml index 8223faed7..fab0615b1 100644 --- a/.github/workflows/golang-test.yml +++ b/.github/workflows/golang-test.yml @@ -46,8 +46,9 @@ jobs: - name: Install modules run: go mod tidy - - name: run build cli + - name: run build client run: GOOS=${{ matrix.os }} go build . + working-directory: client - name: run build management run: GOOS=${{ matrix.os }} go build . diff --git a/.goreleaser.yaml b/.goreleaser.yaml index e25006619..29cc00ac7 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -1,6 +1,8 @@ project_name: wiretrustee builds: - id: wiretrustee + dir: client + binary: wiretrustee env: [CGO_ENABLED=0] goos: diff --git a/cmd/root.go b/client/cmd/root.go similarity index 95% rename from cmd/root.go rename to client/cmd/root.go index 6afc3f7c7..128a9809f 100644 --- a/cmd/root.go +++ b/client/cmd/root.go @@ -12,7 +12,8 @@ import ( const ( // ExitSetupFailed defines exit code - ExitSetupFailed = 1 + ExitSetupFailed = 1 + DefaultConfigPath = "" ) var ( @@ -44,10 +45,8 @@ func init() { } rootCmd.PersistentFlags().StringVar(&configPath, "config", defaultConfigPath, "Wiretrustee config file location to write new config to") rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "") - rootCmd.AddCommand(initCmd) - rootCmd.AddCommand(addPeerCmd) - rootCmd.AddCommand(upCmd) rootCmd.AddCommand(serviceCmd) + rootCmd.AddCommand(upCmd) serviceCmd.AddCommand(runCmd, startCmd, stopCmd, restartCmd) // service control commands are subcommands of service serviceCmd.AddCommand(installCmd, uninstallCmd) // service installer commands are subcommands of service } diff --git a/cmd/service.go b/client/cmd/service.go similarity index 100% rename from cmd/service.go rename to client/cmd/service.go diff --git a/cmd/service_controller.go b/client/cmd/service_controller.go similarity index 98% rename from cmd/service_controller.go rename to client/cmd/service_controller.go index 5b8e1e81d..a2830510e 100644 --- a/cmd/service_controller.go +++ b/client/cmd/service_controller.go @@ -8,7 +8,6 @@ import ( func (p *program) Start(s service.Service) error { // Start should not block. Do the actual work async. logger.Info("Starting service") //nolint - go upCmd.Run(p.cmd, p.args) return nil } diff --git a/cmd/service_installer.go b/client/cmd/service_installer.go similarity index 100% rename from cmd/service_installer.go rename to client/cmd/service_installer.go diff --git a/cmd/service_test.go b/client/cmd/service_test.go similarity index 89% rename from cmd/service_test.go rename to client/cmd/service_test.go index 19cc738de..5b900676d 100644 --- a/cmd/service_test.go +++ b/client/cmd/service_test.go @@ -61,19 +61,6 @@ func Test_ServiceRunCMD(t *testing.T) { } } rootCmd.SetArgs([]string{ - "init", - "--stunURLs", - "stun:stun.wiretrustee.com:3468", - "--signalAddr", - "signal.wiretrustee.com:10000", - "--managementAddr", - "management.wiretrustee.com:10000", - "--turnURLs", - "foo:bar@turn:stun.wiretrustee.com:3468", - "--wgInterface", - "utun99", - "--wgLocalAddr", - "10.100.100.1/24", "--config", configFilePath, }) diff --git a/client/cmd/up.go b/client/cmd/up.go new file mode 100644 index 000000000..b93d5cbe3 --- /dev/null +++ b/client/cmd/up.go @@ -0,0 +1,246 @@ +package cmd + +import ( + "bufio" + "context" + "fmt" + "github.com/pion/ice/v2" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/wiretrustee/wiretrustee/client/internal" + "github.com/wiretrustee/wiretrustee/iface" + mgm "github.com/wiretrustee/wiretrustee/management/client" + mgmProto "github.com/wiretrustee/wiretrustee/management/proto" + signal "github.com/wiretrustee/wiretrustee/signal/client" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "net/url" + "os" + "strings" +) + +var ( + managementAddr string + + upCmd = &cobra.Command{ + Use: "up", + Short: "start wiretrustee", + Run: func(cmd *cobra.Command, args []string) { + InitLog(logLevel) + + config, err := internal.GetConfig(managementAddr, configPath) + if err != nil { + log.Errorf("failed getting config %s %v", configPath, err) + os.Exit(ExitSetupFailed) + } + + //validate our peer's Wireguard PRIVATE key + myPrivateKey, err := wgtypes.ParseKey(config.PrivateKey) + if err != nil { + log.Errorf("failed parsing Wireguard key %s: [%s]", config.PrivateKey, err.Error()) + os.Exit(ExitSetupFailed) + } + + ctx := context.Background() + + managementURL, err := url.Parse(config.ManagementURL) + if err != nil { + log.Errorf("failed parsing managemtn URL%s: [%s]", config.ManagementURL, err.Error()) + os.Exit(ExitSetupFailed) + } + + mgmTlsEnabled := false + if managementURL.Scheme == "https" { + mgmTlsEnabled = true + } + + // connect (just a connection, no stream yet) and login to Management Service to get an initial global Wiretrustee config + + mgmClient, loginResp, err := connectToManagement(ctx, managementURL.Host, myPrivateKey, mgmTlsEnabled) + if err != nil { + log.Error(err) + os.Exit(ExitSetupFailed) + } + + // with the global Wiretrustee config in hand connect (just a connection, no stream yet) Signal + signalClient, err := connectToSignal(ctx, loginResp.GetWiretrusteeConfig(), myPrivateKey) + if err != nil { + log.Error(err) + os.Exit(ExitSetupFailed) + } + + engineConfig, err := createEngineConfig(myPrivateKey, config, loginResp.GetWiretrusteeConfig(), loginResp.GetPeerConfig()) + if err != nil { + log.Error(err) + os.Exit(ExitSetupFailed) + } + + // 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) + err = engine.Start() + if err != nil { + log.Errorf("error while starting Wiretrustee Connection Engine: %s", err) + os.Exit(ExitSetupFailed) + } + + SetupCloseHandler() + <-stopCh + log.Infof("receive signal to stop running") + err = mgmClient.Close() + if err != nil { + log.Errorf("failed closing Management Service client %v", err) + } + err = signalClient.Close() + if err != nil { + log.Errorf("failed closing Signal Service client %v", err) + } + + log.Debugf("removing Wiretrustee interface %s", config.WgIface) + err = iface.Close() + if err != nil { + log.Errorf("failed closing Wiretrustee interface %s %v", config.WgIface, err) + } + }, + } +) + +func init() { + upCmd.PersistentFlags().StringVar(&managementAddr, "management-addr", "", "Management Service address (e.g. app.wiretrustee.com") +} + +// createEngineConfig converts configuration received from Management Service to EngineConfig +func createEngineConfig(key wgtypes.Key, config *internal.Config, wtConfig *mgmProto.WiretrusteeConfig, peerConfig *mgmProto.PeerConfig) (*internal.EngineConfig, error) { + iFaceBlackList := make(map[string]struct{}) + for i := 0; i < len(config.IFaceBlackList); i += 2 { + iFaceBlackList[config.IFaceBlackList[i]] = struct{}{} + } + + stunTurns, err := toStunTurnURLs(wtConfig) + if err != nil { + return nil, status.Errorf(codes.FailedPrecondition, "failed parsing STUN and TURN URLs received from Management Service : %s", err) + } + + return &internal.EngineConfig{ + StunsTurns: stunTurns, + WgIface: config.WgIface, + WgAddr: peerConfig.Address, + IFaceBlackList: iFaceBlackList, + WgPrivateKey: key, + }, nil +} + +// toStunTurnURLs converts Wiretrustee STUN and TURN configs to ice.URL array +func toStunTurnURLs(wtConfig *mgmProto.WiretrusteeConfig) ([]*ice.URL, error) { + + var stunsTurns []*ice.URL + for _, stun := range wtConfig.Stuns { + url, err := ice.ParseURL(stun.Uri) + if err != nil { + return nil, err + } + stunsTurns = append(stunsTurns, url) + } + for _, turn := range wtConfig.Turns { + url, err := ice.ParseURL(turn.HostConfig.Uri) + if err != nil { + return nil, err + } + url.Username = turn.User + url.Password = turn.Password + stunsTurns = append(stunsTurns, url) + } + + return stunsTurns, nil +} + +// connectToSignal creates Signal Service client and established a connection +func connectToSignal(ctx context.Context, wtConfig *mgmProto.WiretrusteeConfig, ourPrivateKey wgtypes.Key) (*signal.Client, error) { + var sigTLSEnabled bool + if wtConfig.Signal.Protocol == mgmProto.HostConfig_HTTPS { + sigTLSEnabled = true + } else { + sigTLSEnabled = false + } + signalClient, err := signal.NewClient(ctx, wtConfig.Signal.Uri, ourPrivateKey, sigTLSEnabled) + if err != nil { + log.Errorf("error while connecting to the Signal Exchange Service %s: %s", wtConfig.Signal.Uri, err) + return nil, status.Errorf(codes.FailedPrecondition, "failed connecting to Signal Service : %s", err) + } + + return signalClient, nil +} + +// connectToManagement creates Management Services client, establishes a connection and gets a global Wiretrustee config (signal, turn, stun hosts, etc) +func connectToManagement(ctx context.Context, managementAddr string, ourPrivateKey wgtypes.Key, tlsEnabled bool) (*mgm.Client, *mgmProto.LoginResponse, error) { + log.Debugf("connecting to management server %s", managementAddr) + mgmClient, err := mgm.NewClient(ctx, managementAddr, ourPrivateKey, tlsEnabled) + if err != nil { + return nil, nil, status.Errorf(codes.FailedPrecondition, "failed connecting to Management Service : %s", err) + } + log.Debugf("connected to management server %s", managementAddr) + + serverKey, err := mgmClient.GetServerPublicKey() + if err != nil { + return nil, nil, status.Errorf(codes.FailedPrecondition, "failed while getting Management Service public key: %s", err) + } + + wtConfig, err := loginPeer(*serverKey, mgmClient) + if err != nil { + return nil, nil, status.Errorf(codes.FailedPrecondition, "failed logging-in peer on Management Service : %s", err) + } + + log.Debugf("peer logged in to Management Service %s", wtConfig) + + return mgmClient, wtConfig, nil +} + +func registerPeer(serverPublicKey wgtypes.Key, client *mgm.Client) (*mgmProto.LoginResponse, error) { + setupKey, err := promptPeerSetupKey() + if err != nil { + log.Errorf("failed getting setup key: %s", err) + return nil, err + } + + log.Debugf("sending peer registration request") + loginResp, err := client.Register(serverPublicKey, *setupKey) + if err != nil { + log.Errorf("failed registering peer %v", err) + return nil, err + } + + return loginResp, nil +} + +func loginPeer(serverPublicKey wgtypes.Key, client *mgm.Client) (*mgmProto.LoginResponse, error) { + + loginResp, err := client.Login(serverPublicKey) + if err != nil { + if s, ok := status.FromError(err); ok && s.Code() == codes.PermissionDenied { + log.Debugf("peer registration required") + return registerPeer(serverPublicKey, client) + } else { + return nil, err + } + } + + return loginResp, nil +} + +// promptPeerSetupKey prompts user to input a Setup Key +func promptPeerSetupKey() (*string, error) { + fmt.Print("Enter setup key: ") + reader := bufio.NewReader(os.Stdin) + input, err := reader.ReadString('\n') + if err != nil { + return nil, err + } + input = strings.TrimSuffix(input, "\n") + + if input == "" { + fmt.Print("Specified key is empty, try again.") + return promptPeerSetupKey() + } + + return &input, err +} diff --git a/connection/cond.go b/client/internal/cond.go similarity index 97% rename from connection/cond.go rename to client/internal/cond.go index 9790e4d9c..06aff312c 100644 --- a/connection/cond.go +++ b/client/internal/cond.go @@ -1,4 +1,4 @@ -package connection +package internal import "sync" diff --git a/client/internal/config.go b/client/internal/config.go new file mode 100644 index 000000000..f64f26856 --- /dev/null +++ b/client/internal/config.go @@ -0,0 +1,72 @@ +package internal + +import ( + log "github.com/sirupsen/logrus" + "github.com/wiretrustee/wiretrustee/iface" + "github.com/wiretrustee/wiretrustee/util" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + "os" +) + +const ManagementAddrDefault = "https://app.wiretrustee.com" + +// Config Configuration type +type Config struct { + // Wireguard private key of local peer + PrivateKey string + ManagementURL string + WgIface string + IFaceBlackList []string +} + +//createNewConfig creates a new config generating a new Wireguard key and saving to file +func createNewConfig(managementURL string, configPath string) (*Config, error) { + wgKey := generateKey() + config := &Config{PrivateKey: wgKey, WgIface: iface.WgInterfaceDefault, IFaceBlackList: []string{}} + if managementURL != "" { + config.ManagementURL = managementURL + } else { + config.ManagementURL = ManagementAddrDefault + } + + err := util.WriteJson(configPath, config) + if err != nil { + return nil, err + } + + return config, nil +} + +// GetConfig reads existing config or generates a new one +func GetConfig(managementURL string, configPath string) (*Config, error) { + + var config *Config + if _, err := os.Stat(configPath); os.IsNotExist(err) { + log.Warnf("first run - generating new config %s", configPath) + config, err = createNewConfig(managementURL, configPath) + if err != nil { + return nil, err + } + } else { + config = &Config{} + _, err := util.ReadJson(configPath, config) + if err != nil { + return nil, err + } + } + + if managementURL != "" { + config.ManagementURL = managementURL + } + + return config, nil +} + +// generateKey generates a new Wireguard private key +func generateKey() string { + key, err := wgtypes.GenerateKey() + if err != nil { + panic(err) + } + return key.String() +} diff --git a/connection/connection.go b/client/internal/connection.go similarity index 85% rename from connection/connection.go rename to client/internal/connection.go index 76bbb56ab..fb8a5556e 100644 --- a/connection/connection.go +++ b/client/internal/connection.go @@ -1,4 +1,4 @@ -package connection +package internal import ( "context" @@ -7,6 +7,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/wiretrustee/wiretrustee/iface" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + "net" "sync" "time" ) @@ -14,6 +15,7 @@ import ( var ( // DefaultWgKeepAlive default Wireguard keep alive constant DefaultWgKeepAlive = 20 * time.Second + privateIPBlocks []*net.IPNet ) type Status string @@ -24,6 +26,25 @@ const ( StatusDisconnected Status = "Disconnected" ) +func init() { + for _, cidr := range []string{ + "127.0.0.0/8", // IPv4 loopback + "10.0.0.0/8", // RFC1918 + "172.16.0.0/12", // RFC1918 + "192.168.0.0/16", // RFC1918 + "169.254.0.0/16", // RFC3927 link-local + "::1/128", // IPv6 loopback + "fe80::/10", // IPv6 link-local + "fc00::/7", // IPv6 unique local addr + } { + _, block, err := net.ParseCIDR(cidr) + if err != nil { + panic(fmt.Errorf("parse error on %q: %v", cidr, err)) + } + privateIPBlocks = append(privateIPBlocks, block) + } +} + // ConnConfig Connection configuration struct type ConnConfig struct { // Local Wireguard listening address e.g. 127.0.0.1:51820 @@ -162,14 +183,17 @@ func (conn *Connection) Open(timeout time.Duration) error { if err != nil { return err } - // in case the remote peer is in the local network we don't need a Wireguard proxy, direct communication is possible. - if pair.Local.Type() == ice.CandidateTypeHost && pair.Remote.Type() == ice.CandidateTypeHost { - log.Debugf("remote peer %s is in the local network with an address %s", conn.Config.RemoteWgKey.String(), pair.Remote.Address()) + remoteIP := net.ParseIP(pair.Remote.Address()) + myIp := net.ParseIP(pair.Remote.Address()) + // in case the remote peer is in the local network or one of the peers has public static IP -> no need for a Wireguard proxy, direct communication is possible. + if (pair.Local.Type() == ice.CandidateTypeHost && pair.Remote.Type() == ice.CandidateTypeHost) && (isPublicIP(remoteIP) || isPublicIP(myIp)) { + log.Debugf("it is possible to establish a direct connection (without proxy) to peer %s - my addr: %s, remote addr: %s", conn.Config.RemoteWgKey.String(), pair.Local.Address(), pair.Remote.Address()) err = conn.wgProxy.StartLocal(fmt.Sprintf("%s:%d", pair.Remote.Address(), iface.WgPort)) if err != nil { return err } } else { + log.Infof("establishing secure tunnel to peer %s via selected candidate pair %s", conn.Config.RemoteWgKey.String(), pair) err = conn.wgProxy.Start(remoteConn) if err != nil { return err @@ -196,6 +220,19 @@ func (conn *Connection) Open(timeout time.Duration) error { return fmt.Errorf("connection to peer %s has been closed", conn.Config.RemoteWgKey.String()) } +func isPublicIP(ip net.IP) bool { + if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() { + return false + } + + for _, block := range privateIPBlocks { + if block.Contains(ip) { + return false + } + } + return true +} + // Close Closes a peer connection func (conn *Connection) Close() error { var err error @@ -329,7 +366,7 @@ func (conn *Connection) listenOnConnectionStateChanges() error { log.Errorf("failed selecting active ICE candidate pair %s", err) return } - log.Infof("will connect to peer %s via a selected connnection candidate pair %s", conn.Config.RemoteWgKey.String(), pair) + log.Debugf("ICE connected to peer %s via a selected connnection candidate pair %s", conn.Config.RemoteWgKey.String(), pair) } else if state == ice.ConnectionStateDisconnected || state == ice.ConnectionStateFailed { err := conn.Close() if err != nil { diff --git a/connection/engine.go b/client/internal/engine.go similarity index 52% rename from connection/engine.go rename to client/internal/engine.go index 3506bd2c3..8754c58c8 100644 --- a/connection/engine.go +++ b/client/internal/engine.go @@ -1,4 +1,4 @@ -package connection +package internal import ( "fmt" @@ -6,9 +6,12 @@ import ( ice "github.com/pion/ice/v2" log "github.com/sirupsen/logrus" "github.com/wiretrustee/wiretrustee/iface" + mgm "github.com/wiretrustee/wiretrustee/management/client" + mgmProto "github.com/wiretrustee/wiretrustee/management/proto" signal "github.com/wiretrustee/wiretrustee/signal/client" sProto "github.com/wiretrustee/wiretrustee/signal/proto" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + "strings" "sync" "time" ) @@ -17,22 +20,37 @@ import ( // E.g. this peer will wait PeerConnectionTimeout for the remote peer to respond, if not successful then it will retry the connection attempt. const PeerConnectionTimeout = 60 * time.Second -// Engine is an instance of the Connection Engine +// EngineConfig is a config for the Engine +type EngineConfig struct { + // StunsTurns is a list of STUN and TURN servers used by ICE + StunsTurns []*ice.URL + WgIface string + // WgAddr is a Wireguard local address (Wiretrustee Network IP) + WgAddr string + // WgPrivateKey is a Wireguard private key of our peer (it MUST never leave the machine) + WgPrivateKey wgtypes.Key + // IFaceBlackList is a list of network interfaces to ignore when discovering connection candidates (ICE related) + IFaceBlackList map[string]struct{} +} + +// Engine is a mechanism responsible for reacting on Signal and Management stream events and managing connections to the remote peers. type Engine struct { - // a list of STUN and TURN servers - stunsTurns []*ice.URL - // signal server client + // signal is a Signal Service client signal *signal.Client - // peer agents indexed by local public key of the remote peers + // mgmClient is a Management Service client + mgmClient *mgm.Client + // conns is a collection of remote peer connections indexed by local public key of the remote peers conns map[string]*Connection - // Wireguard interface - wgIface string - // Wireguard local address - wgIP string - // Network Interfaces to ignore - iFaceBlackList map[string]struct{} - // PeerMux is used to sync peer operations (e.g. open connection, peer removal) - PeerMux *sync.Mutex + + // peerMux is used to sync peer operations (e.g. open connection, peer removal) + peerMux *sync.Mutex + // syncMsgMux is used to guarantee sequential Management Service message processing + syncMsgMux *sync.Mutex + + config *EngineConfig + + // wgPort is a Wireguard local listen port + wgPort int } // Peer is an instance of the Connection Peer @@ -42,52 +60,53 @@ type Peer struct { } // NewEngine creates a new Connection Engine -func NewEngine(signal *signal.Client, stunsTurns []*ice.URL, wgIface string, wgAddr string, - iFaceBlackList map[string]struct{}) *Engine { +func NewEngine(signalClient *signal.Client, mgmClient *mgm.Client, config *EngineConfig) *Engine { return &Engine{ - stunsTurns: stunsTurns, - signal: signal, - wgIface: wgIface, - wgIP: wgAddr, - conns: map[string]*Connection{}, - iFaceBlackList: iFaceBlackList, - PeerMux: &sync.Mutex{}, + signal: signalClient, + mgmClient: mgmClient, + conns: map[string]*Connection{}, + peerMux: &sync.Mutex{}, + syncMsgMux: &sync.Mutex{}, + config: config, } } -// Start creates a new tunnel interface and listens to signals from the Signal service. -// It also creates an Go routine to handle each peer communication from the config file -func (e *Engine) Start(myKey wgtypes.Key, peers []Peer) error { +// Start creates a new Wireguard tunnel interface and listens to events from Signal and Management services +// Connections to remote peers are not established here. +// However, they will be established once an event with a list of peers to connect to will be received from Management Service +func (e *Engine) Start() error { - err := iface.Create(e.wgIface, e.wgIP) + wgIface := e.config.WgIface + wgAddr := e.config.WgAddr + myPrivateKey := e.config.WgPrivateKey + + err := iface.Create(wgIface, wgAddr) if err != nil { - log.Errorf("error while creating interface %s: [%s]", e.wgIface, err.Error()) + log.Errorf("failed creating interface %s: [%s]", wgIface, err.Error()) return err } - err = iface.Configure(e.wgIface, myKey.String()) + err = iface.Configure(wgIface, myPrivateKey.String()) if err != nil { - log.Errorf("error while configuring Wireguard interface [%s]: %s", e.wgIface, err.Error()) + log.Errorf("failed configuring Wireguard interface [%s]: %s", wgIface, err.Error()) return err } - wgPort, err := iface.GetListenPort(e.wgIface) + port, err := iface.GetListenPort(wgIface) if err != nil { - log.Errorf("error while getting Wireguard interface port [%s]: %s", e.wgIface, err.Error()) + log.Errorf("failed getting Wireguard listen port [%s]: %s", wgIface, err.Error()) return err } + e.wgPort = *port - e.receiveSignal() + e.receiveSignalEvents() + e.receiveManagementEvents() - for _, peer := range peers { - peer := peer - go e.InitializePeer(*wgPort, myKey, peer) - } return nil } -// InitializePeer peer agent attempt to open connection -func (e *Engine) InitializePeer(wgPort int, myKey wgtypes.Key, peer Peer) { +// initializePeer peer agent attempt to open connection +func (e *Engine) initializePeer(peer Peer) { var backOff = &backoff.ExponentialBackOff{ InitialInterval: backoff.DefaultInitialInterval, RandomizationFactor: backoff.DefaultRandomizationFactor, @@ -98,9 +117,9 @@ func (e *Engine) InitializePeer(wgPort int, myKey wgtypes.Key, peer Peer) { Clock: backoff.SystemClock, } operation := func() error { - _, err := e.openPeerConnection(wgPort, myKey, peer) - e.PeerMux.Lock() - defer e.PeerMux.Unlock() + _, err := e.openPeerConnection(e.wgPort, e.config.WgPrivateKey, peer) + e.peerMux.Lock() + defer e.peerMux.Unlock() if _, ok := e.conns[peer.WgPubKey]; !ok { log.Infof("removing connection attempt with Peer: %v, not retrying", peer.WgPubKey) return nil @@ -121,13 +140,23 @@ func (e *Engine) InitializePeer(wgPort int, myKey wgtypes.Key, peer Peer) { } } -// RemovePeerConnection closes existing peer connection and removes peer -func (e *Engine) RemovePeerConnection(peer Peer) error { - e.PeerMux.Lock() - defer e.PeerMux.Unlock() - conn, exists := e.conns[peer.WgPubKey] +func (e *Engine) removePeerConnections(peers []string) error { + e.peerMux.Lock() + defer e.peerMux.Unlock() + for _, peer := range peers { + err := e.removePeerConnection(peer) + if err != nil { + return err + } + } + return nil +} + +// removePeerConnection closes existing peer connection and removes peer +func (e *Engine) removePeerConnection(peerKey string) error { + conn, exists := e.conns[peerKey] if exists && conn != nil { - delete(e.conns, peer.WgPubKey) + delete(e.conns, peerKey) return conn.Close() } return nil @@ -135,8 +164,8 @@ func (e *Engine) RemovePeerConnection(peer Peer) error { // GetPeerConnectionStatus returns a connection Status or nil if peer connection wasn't found func (e *Engine) GetPeerConnectionStatus(peerKey string) *Status { - e.PeerMux.Lock() - defer e.PeerMux.Unlock() + e.peerMux.Lock() + defer e.peerMux.Unlock() conn, exists := e.conns[peerKey] if exists && conn != nil { @@ -146,20 +175,20 @@ func (e *Engine) GetPeerConnectionStatus(peerKey string) *Status { return nil } -// opens a new peer connection +// openPeerConnection opens a new remote peer connection func (e *Engine) openPeerConnection(wgPort int, myKey wgtypes.Key, peer Peer) (*Connection, error) { - e.PeerMux.Lock() + e.peerMux.Lock() remoteKey, _ := wgtypes.ParseKey(peer.WgPubKey) connConfig := &ConnConfig{ WgListenAddr: fmt.Sprintf("127.0.0.1:%d", wgPort), - WgPeerIP: e.wgIP, - WgIface: e.wgIface, + WgPeerIP: e.config.WgAddr, + WgIface: e.config.WgIface, WgAllowedIPs: peer.WgAllowedIps, WgKey: myKey, RemoteWgKey: remoteKey, - StunTurnURLS: e.stunsTurns, - iFaceBlackList: e.iFaceBlackList, + StunTurnURLS: e.config.StunsTurns, + iFaceBlackList: e.config.IFaceBlackList, } signalOffer := func(uFrag string, pwd string) error { @@ -174,7 +203,7 @@ func (e *Engine) openPeerConnection(wgPort int, myKey wgtypes.Key, peer Peer) (* } conn := NewConnection(*connConfig, signalCandidate, signalOffer, signalAnswer) e.conns[remoteKey.String()] = conn - e.PeerMux.Unlock() + e.peerMux.Unlock() // blocks until the connection is open (or timeout) err := conn.Open(PeerConnectionTimeout) @@ -225,10 +254,67 @@ func signalAuth(uFrag string, pwd string, myKey wgtypes.Key, remoteKey wgtypes.K return nil } -func (e *Engine) receiveSignal() { +// receiveManagementEvents connects to the Management Service event stream to receive updates from the management service +// E.g. when a new peer has been registered and we are allowed to connect to it. +func (e *Engine) receiveManagementEvents() { + + log.Debugf("connecting to Management Service updates stream") + + e.mgmClient.Sync(func(update *mgmProto.SyncResponse) error { + // todo handle changes of global settings (in update.GetWiretrusteeConfig()) + // todo handle changes of peer settings (in update.GetPeerConfig()) + + e.syncMsgMux.Lock() + defer e.syncMsgMux.Unlock() + + remotePeers := update.GetRemotePeers() + if len(remotePeers) != 0 { + + remotePeerMap := make(map[string]struct{}) + for _, peer := range remotePeers { + remotePeerMap[peer.GetWgPubKey()] = struct{}{} + } + + //remove peers that are no longer available for us + toRemove := []string{} + for p := range e.conns { + if _, ok := remotePeerMap[p]; !ok { + toRemove = append(toRemove, p) + } + } + err := e.removePeerConnections(toRemove) + if err != nil { + return err + } + + // add new peers + for _, peer := range remotePeers { + peerKey := peer.GetWgPubKey() + peerIPs := peer.GetAllowedIps() + if _, ok := e.conns[peerKey]; !ok { + go e.initializePeer(Peer{ + WgPubKey: peerKey, + WgAllowedIps: strings.Join(peerIPs, ","), + }) + } + + } + } + + return nil + }) + + log.Infof("connected to Management Service updates stream") +} + +// receiveSignalEvents connects to the Signal Service event stream to negotiate connection with remote peers +func (e *Engine) receiveSignalEvents() { // connect to a stream of messages coming from the signal server e.signal.Receive(func(msg *sProto.Message) error { + e.syncMsgMux.Lock() + defer e.syncMsgMux.Unlock() + conn := e.conns[msg.Key] if conn == nil { return fmt.Errorf("wrongly addressed message %s", msg.Key) diff --git a/connection/engine_test.go b/client/internal/engine_test.go similarity index 79% rename from connection/engine_test.go rename to client/internal/engine_test.go index 932c24980..3229b1fa3 100644 --- a/connection/engine_test.go +++ b/client/internal/engine_test.go @@ -1,12 +1,13 @@ -package connection +package internal import ( "context" "fmt" - ice "github.com/pion/ice/v2" + "github.com/pion/ice/v2" log "github.com/sirupsen/logrus" "github.com/wiretrustee/wiretrustee/iface" - signal "github.com/wiretrustee/wiretrustee/signal/client" + mgmClient "github.com/wiretrustee/wiretrustee/management/client" + signalClient "github.com/wiretrustee/wiretrustee/signal/client" "golang.zx2c4.com/wireguard/wgctrl" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" "testing" @@ -39,17 +40,25 @@ func Test_Start(t *testing.T) { iFaceBlackList := make(map[string]struct{}) - var sigTLSEnabled = false - - signalClient, err := signal.NewClient(ctx, "signal.wiretrustee.com:10000", testKey, sigTLSEnabled) + signal, err := signalClient.NewClient(ctx, "signal.wiretrustee.com:10000", testKey, false) if err != nil { t.Fatal(err) } - engine = NewEngine(signalClient, stunURLs, ifaceName, "10.99.91.1/24", iFaceBlackList) + mgm, err := mgmClient.NewClient(ctx, "app.wiretrustee.com:33073", testKey, true) + if err != nil { + t.Fatal(err) + } + conf := &EngineConfig{ + StunsTurns: stunURLs, + WgIface: ifaceName, + WgAddr: "10.99.91.1/24", + WgPrivateKey: testKey, + IFaceBlackList: iFaceBlackList, + } + engine = NewEngine(signal, mgm, conf) - var emptyPeer []Peer - err = engine.Start(testKey, emptyPeer) + err = engine.Start() if err != nil { t.Fatal(err) } @@ -74,7 +83,7 @@ func TestEngine_InitializePeerWithoutRemote(t *testing.T) { tmpKey.PublicKey().String(), "10.99.91.2/32", } - go engine.InitializePeer(iface.WgPort, testKey, testPeer) + go engine.initializePeer(testPeer) // Let the connections initialize ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() @@ -108,8 +117,8 @@ func TestEngine_Initialize2PeersWithoutRemote(t *testing.T) { tmpKey2.PublicKey().String(), "10.99.91.3/32", } - go engine.InitializePeer(iface.WgPort, testKey, testPeer1) - go engine.InitializePeer(iface.WgPort, testKey, testPeer2) + go engine.initializePeer(testPeer1) + go engine.initializePeer(testPeer2) // Let the connections initialize ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() @@ -146,7 +155,7 @@ func TestEngine_RemovePeerConnectionWithoutRemote(t *testing.T) { } // Let the connections close - err := engine.RemovePeerConnection(testPeer) + err := engine.removePeerConnection(testPeer.WgPubKey) if err != nil { t.Fatal(err) } diff --git a/connection/wgproxy.go b/client/internal/wgproxy.go similarity index 99% rename from connection/wgproxy.go rename to client/internal/wgproxy.go index 153aa0824..0c5f48148 100644 --- a/connection/wgproxy.go +++ b/client/internal/wgproxy.go @@ -1,4 +1,4 @@ -package connection +package internal import ( ice "github.com/pion/ice/v2" diff --git a/main.go b/client/main.go similarity index 67% rename from main.go rename to client/main.go index 0a71638c8..0a85983f1 100644 --- a/main.go +++ b/client/main.go @@ -1,7 +1,7 @@ package main import ( - "github.com/wiretrustee/wiretrustee/cmd" + "github.com/wiretrustee/wiretrustee/client/cmd" "os" ) diff --git a/cmd/addpeer.go b/cmd/addpeer.go deleted file mode 100644 index 60efe715b..000000000 --- a/cmd/addpeer.go +++ /dev/null @@ -1,59 +0,0 @@ -package cmd - -import ( - "os" - - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "github.com/wiretrustee/wiretrustee/connection" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -var ( - key string - allowedIPs string - - addPeerCmd = &cobra.Command{ - Use: "add-peer", - Short: "add remote peer", - Run: func(cmd *cobra.Command, args []string) { - InitLog(logLevel) - err := addPeer(key, allowedIPs) - if err != nil { - log.Errorf("Failed to add peer: %s", err) - os.Exit(ExitSetupFailed) - } - }, - } -) - -func init() { - addPeerCmd.PersistentFlags().StringVar(&key, "key", "", "Wireguard public key of the remote peer") - addPeerCmd.PersistentFlags().StringVar(&allowedIPs, "allowedIPs", "", "Wireguard Allowed IPs for the remote peer, e.g 10.30.30.2/32") - addPeerCmd.MarkPersistentFlagRequired("key") //nolint - addPeerCmd.MarkPersistentFlagRequired("allowedIPs") //nolint -} - -func addPeer(peerKey string, allowedIPs string) error { - if _, err := os.Stat(configPath); os.IsNotExist(err) { - return status.Errorf(codes.FailedPrecondition, "Config doesn't exist, please run 'wiretrustee init' first") - } - - config, err := Read(configPath) - if err != nil { - return status.Errorf(codes.FailedPrecondition, "Error reading config file, message: %s", err) - } - config.Peers = append(config.Peers, connection.Peer{ - WgPubKey: key, - WgAllowedIps: allowedIPs, - }) - - err = config.Write(configPath) - if err != nil { - log.Errorf("failed writing config to %s: %s", config, err.Error()) - return status.Errorf(codes.Internal, "failed writing config to %s: %s", configPath, err) - } - - return nil -} diff --git a/cmd/config.go b/cmd/config.go deleted file mode 100644 index 70eb6f608..000000000 --- a/cmd/config.go +++ /dev/null @@ -1,71 +0,0 @@ -package cmd - -import ( - "encoding/json" - "io/ioutil" - "os" - "path/filepath" - - ice "github.com/pion/ice/v2" - "github.com/wiretrustee/wiretrustee/connection" -) - -// Config Configuration type -type Config struct { - // Wireguard private key of local peer - PrivateKey string - Peers []connection.Peer - StunTurnURLs []*ice.URL - // host:port of the signal server - SignalAddr string - ManagementAddr string - WgAddr string - WgIface string - IFaceBlackList []string -} - -//Write writes configPath to a file -func (cfg *Config) Write(path string) error { - - if path == defaultConfigPath { - configDir := filepath.Dir(path) - err := os.MkdirAll(configDir, 0750) - if err != nil { - return err - } - } - - bs, err := json.Marshal(cfg) - if err != nil { - return err - } - - err = ioutil.WriteFile(path, bs, 0600) - if err != nil { - return err - } - - return nil -} - -//Read reads configPath from a file -func Read(path string) (*Config, error) { - f, err := os.Open(path) - if err != nil { - return nil, err - } - defer f.Close() - - bs, err := ioutil.ReadAll(f) - if err != nil { - return nil, err - } - - var cfg Config - err = json.Unmarshal(bs, &cfg) - if err != nil { - return nil, err - } - - return &cfg, nil -} diff --git a/cmd/init.go b/cmd/init.go deleted file mode 100644 index 9ff604cbf..000000000 --- a/cmd/init.go +++ /dev/null @@ -1,130 +0,0 @@ -package cmd - -import ( - "os" - "strings" - - ice "github.com/pion/ice/v2" - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" -) - -var ( - wgKey string - wgInterface string - wgLocalAddr string - signalAddr string - managementAddr string - stunURLs string - turnURLs string - - initCmd = &cobra.Command{ - Use: "init", - Short: "init wiretrustee", - Run: func(cmd *cobra.Command, args []string) { - InitLog(logLevel) - - if _, err := os.Stat(configPath); !os.IsNotExist(err) { - log.Warnf("config already exists under path %s", configPath) - os.Exit(ExitSetupFailed) - } - - if wgKey == "" { - wgKey = generateKey() - log.Warnf("there was no Wireguard private key specified, a new Wireguard key has been generated") - } - - parsedKey, err := wgtypes.ParseKey(wgKey) - if err != nil { - log.Errorf("invalid Wireguard private key %s", wgKey) - os.Exit(ExitSetupFailed) - } - - log.Infof("my public Wireguard key is %s", parsedKey.PublicKey().String()) - - var stunTurnURLs []*ice.URL - stuns := strings.Split(stunURLs, ",") - for _, url := range stuns { - - parsedURL, err := ice.ParseURL(url) - if err != nil { - log.Errorf("failed parsing STUN URL %s: %s", url, err.Error()) - os.Exit(ExitSetupFailed) - } - stunTurnURLs = append(stunTurnURLs, parsedURL) - } - - turns := strings.Split(turnURLs, ",") - for _, url := range turns { - - var urlToParse string - var user string - var pwd string - //extract user:password from user:password@proto:host:port - urlSplit := strings.Split(url, "@") - if len(urlSplit) == 2 { - urlToParse = urlSplit[1] - credential := strings.Split(urlSplit[0], ":") - user = credential[0] - pwd = credential[1] - } else { - urlToParse = url - } - - parsedURL, err := ice.ParseURL(urlToParse) - if err != nil { - log.Errorf("failed parsing TURN URL %s: %s", url, err.Error()) - os.Exit(ExitSetupFailed) - } - parsedURL.Username = user - parsedURL.Password = pwd - stunTurnURLs = append(stunTurnURLs, parsedURL) - } - - config := &Config{ - PrivateKey: wgKey, - Peers: nil, - StunTurnURLs: stunTurnURLs, - SignalAddr: signalAddr, - ManagementAddr: managementAddr, - WgAddr: wgLocalAddr, - WgIface: wgInterface, - } - - err = config.Write(configPath) - if err != nil { - log.Errorf("failed writing config to %s: %s", config, err.Error()) - os.Exit(ExitSetupFailed) - } - - log.Infof("a new config has been generated and written to %s", configPath) - }, - } -) - -func init() { - initCmd.PersistentFlags().StringVar(&wgKey, "wgKey", "", "Wireguard private key, if not specified a new one will be generated") - initCmd.PersistentFlags().StringVar(&wgInterface, "wgInterface", "wiretrustee0", "Wireguard interface name, e.g. wiretreustee0 or wg0") - initCmd.PersistentFlags().StringVar(&wgLocalAddr, "wgLocalAddr", "", "Wireguard local address, e.g. 10.30.30.1/24") - initCmd.PersistentFlags().StringVar(&signalAddr, "signalAddr", "", "Signal server address, e.g. signal.wiretrustee.com:10000") - initCmd.PersistentFlags().StringVar(&managementAddr, "managementAddr", "", "Management server address, e.g. management.wiretrustee.com:10000") - initCmd.PersistentFlags().StringVar(&stunURLs, "stunURLs", "", "Comma separated STUN server URLs: protocol:host:port, e.g. stun:stun.l.google.com:19302,stun:stun1.l.google.com:19302") - //todo user:password@protocol:host:port not the best way to pass TURN credentials, do it according to https://tools.ietf.org/html/rfc7065 E.g. use oauth - initCmd.PersistentFlags().StringVar(&turnURLs, "turnURLs", "", "Comma separated TURN server URLs: user:password@protocol:host:port, e.g. user:password@turn:stun.wiretrustee.com:3468") - //initCmd.MarkPersistentFlagRequired("configPath") - initCmd.MarkPersistentFlagRequired("wgLocalAddr") //nolint - initCmd.MarkPersistentFlagRequired("signalAddr") //nolint - initCmd.MarkPersistentFlagRequired("managementAddr") //nolint - initCmd.MarkPersistentFlagRequired("stunURLs") //nolint - initCmd.MarkPersistentFlagRequired("turnURLs") //nolint -} - -// generateKey generates a new Wireguard private key -func generateKey() string { - key, err := wgtypes.GenerateKey() - if err != nil { - panic(err) - } - return key.String() -} diff --git a/cmd/up.go b/cmd/up.go deleted file mode 100644 index 85e7a9d2d..000000000 --- a/cmd/up.go +++ /dev/null @@ -1,177 +0,0 @@ -package cmd - -import ( - "context" - signal "github.com/wiretrustee/wiretrustee/signal/client" - "io" - "os" - "strings" - "time" - - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "github.com/wiretrustee/wiretrustee/connection" - "github.com/wiretrustee/wiretrustee/encryption" - mgm "github.com/wiretrustee/wiretrustee/management/proto" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/keepalive" - "google.golang.org/grpc/status" -) - -var ( - setupKey string - - upCmd = &cobra.Command{ - Use: "up", - Short: "start wiretrustee", - Run: func(cmd *cobra.Command, args []string) { - InitLog(logLevel) - - config, err := Read(configPath) - if err != nil { - log.Fatalf("Error reading config file, message: %v", err) - } - - myKey, err := wgtypes.ParseKey(config.PrivateKey) - if err != nil { - log.Errorf("failed parsing Wireguard key %s: [%s]", config.PrivateKey, err.Error()) - os.Exit(ExitSetupFailed) - } - - go processManagement(config.ManagementAddr, setupKey, myKey) - - var sigTLSEnabled = false - ctx := context.Background() - signalClient, err := signal.NewClient(ctx, config.SignalAddr, myKey, sigTLSEnabled) - if err != nil { - log.Errorf("error while connecting to the Signal Exchange Service %s: %s", config.SignalAddr, err) - os.Exit(ExitSetupFailed) - } - //todo proper close handling - defer func() { signalClient.Close() }() - - iFaceBlackList := make(map[string]struct{}) - for i := 0; i < len(config.IFaceBlackList); i += 2 { - iFaceBlackList[config.IFaceBlackList[i]] = struct{}{} - } - engine := connection.NewEngine(signalClient, config.StunTurnURLs, config.WgIface, config.WgAddr, iFaceBlackList) - - err = engine.Start(myKey, config.Peers) - if err != nil { - log.Errorf("error while starting the engine: %s", err) - os.Exit(ExitSetupFailed) - } - //signalClient.WaitConnected() - - SetupCloseHandler() - <-stopCh - log.Println("Receive signal to stop running") - }, - } -) - -func init() { - upCmd.PersistentFlags().StringVar(&setupKey, "setupKey", "", "Setup key to join a network, if not specified a new network will be created") -} - -func processManagement(managementAddr string, setupKey string, ourPrivateKey wgtypes.Key) { - err := connectToManagement(managementAddr, setupKey, ourPrivateKey) - if err != nil { - log.Errorf("Failed to connect to managment server: %s", err) - os.Exit(ExitSetupFailed) - } - - for { - _ = connectToManagement(managementAddr, setupKey, ourPrivateKey) - } -} - -func connectToManagement(managementAddr string, setupKey string, ourPrivateKey wgtypes.Key) error { - log.Printf("Connecting to management server %s", managementAddr) - mgmCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - mgmConn, err := grpc.DialContext( - mgmCtx, - managementAddr, - grpc.WithInsecure(), - grpc.WithBlock(), - grpc.WithKeepaliveParams(keepalive.ClientParameters{ - Time: 3 * time.Second, - Timeout: 2 * time.Second, - })) - - if err != nil { - return status.Errorf(codes.FailedPrecondition, "Error while connecting to the Management Service %s: %s", managementAddr, err) - } - defer mgmConn.Close() - - log.Printf("Connected to management server %s", managementAddr) - - mgmClient := mgm.NewManagementServiceClient(mgmConn) - serverKeyResponse, err := mgmClient.GetServerKey(mgmCtx, &mgm.Empty{}) - if err != nil { - return status.Errorf(codes.FailedPrecondition, "Error while getting server key: %s", err) - } - - serverKey, err := wgtypes.ParseKey(serverKeyResponse.Key) - if err != nil { - return status.Errorf(codes.FailedPrecondition, "Failed parsing Wireguard public server key %s: [%s]", serverKeyResponse.Key, err) - } - - _, err = mgmClient.RegisterPeer(mgmCtx, &mgm.RegisterPeerRequest{Key: ourPrivateKey.PublicKey().String(), SetupKey: setupKey}) - if err != nil { - return status.Errorf(codes.FailedPrecondition, "Error while registering account: %s", err) - } - - log.Println("Peer registered") - updatePeers(mgmClient, serverKey, ourPrivateKey) - return nil -} - -func updatePeers(mgmClient mgm.ManagementServiceClient, remotePubKey wgtypes.Key, ourPrivateKey wgtypes.Key) { - log.Printf("Getting peers updates") - ctx := context.Background() - req := &mgm.SyncRequest{} - encryptedReq, err := encryption.EncryptMessage(remotePubKey, ourPrivateKey, req) - if err != nil { - log.Errorf("Failed to encrypt message: %s", err) - return - } - - syncReq := &mgm.EncryptedMessage{WgPubKey: ourPrivateKey.PublicKey().String(), Body: encryptedReq} - stream, err := mgmClient.Sync(ctx, syncReq) - if err != nil { - log.Errorf("Failed to open management stream: %s", err) - return - } - for { - update, err := stream.Recv() - if err == io.EOF { - log.Errorf("Managment stream was closed: %s", err) - return - } - if err != nil { - log.Errorf("Managment stream disconnected: %s", err) - return - } - - log.Infof("Got peers update") - resp := &mgm.SyncResponse{} - err = encryption.DecryptMessage(remotePubKey, ourPrivateKey, update.Body, resp) - if err != nil { - log.Errorf("Failed to decrypt message: %s", err) - return - } - - for _, peer := range resp.RemotePeers { - log.Infof("Peer: %s", peer) - _ = addPeer(peer.WgPubKey, strings.Join(peer.AllowedIps, ",")) - } - - // for _, peer := range resp.RemotePeers { - // log.Infof("Peer: %s", peer.WgPubKey) - //} - } -} diff --git a/go.mod b/go.mod index d10e7d880..e3cb941aa 100644 --- a/go.mod +++ b/go.mod @@ -3,29 +3,22 @@ module github.com/wiretrustee/wiretrustee go 1.16 require ( - github.com/auth0/go-jwt-middleware v1.0.1 github.com/cenkalti/backoff/v4 v4.1.0 - github.com/codegangsta/negroni v1.0.0 - github.com/coreos/go-oidc v2.2.1+incompatible github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang/protobuf v1.5.2 github.com/google/uuid v1.2.0 - github.com/gorilla/mux v1.8.0 // indirect - github.com/gorilla/sessions v1.2.1 github.com/kardianos/service v1.2.0 github.com/onsi/ginkgo v1.16.4 github.com/onsi/gomega v1.13.0 github.com/pion/ice/v2 v2.1.7 - github.com/pquerna/cachecontrol v0.1.0 // indirect github.com/sirupsen/logrus v1.7.0 github.com/spf13/cobra v1.1.3 github.com/vishvananda/netlink v1.1.0 - golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 - golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2 - golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5 - golang.zx2c4.com/wireguard/windows v0.3.14 + golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 + golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c + golang.zx2c4.com/wireguard v0.0.0-20210805125648-3957e9b9dd19 + golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c + golang.zx2c4.com/wireguard/windows v0.4.5 google.golang.org/grpc v1.32.0 google.golang.org/protobuf v1.26.0 - gopkg.in/square/go-jose.v2 v2.6.0 // indirect ) diff --git a/go.sum b/go.sum index e70fd0f36..d9bfe9448 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,6 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/auth0/go-jwt-middleware v1.0.1 h1:/fsQ4vRr4zod1wKReUH+0A3ySRjGiT9G34kypO/EKwI= -github.com/auth0/go-jwt-middleware v1.0.1/go.mod h1:YSeUX3z6+TF2H+7padiEqNJ73Zy9vXW72U//IgN0BIM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -31,12 +29,8 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY= -github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= -github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= @@ -50,8 +44,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -103,15 +95,6 @@ github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0= -github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= -github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -152,7 +135,6 @@ github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b h1:c3NTyLNozI github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kardianos/service v1.2.0 h1:bGuZ/epo3vrt8IPC7mnKQolqFeYJb7Cs8Rk4PSOBB/g= @@ -240,8 +222,6 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc= -github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -262,9 +242,6 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0= -github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -287,8 +264,6 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k= @@ -311,8 +286,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf h1:B2n+Zi5QeYRDAEodEu72OS36gmTWjgpXr2+cWcBW90o= -golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -363,11 +338,10 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -416,8 +390,9 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -425,8 +400,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f h1:yQJrRE0hDxDFmZLlRaw+3vusO4fwNHgHIjUOMO7bHYI= -golang.org/x/text v0.3.7-0.20210503195748-5c7c50ebbd4f/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.7-0.20210524175448-3115f89c4b99 h1:ZEXtoJu1S0ie/EmdYnjY3CqaCCZxnldL+K1ftMITD2Q= +golang.org/x/text v0.3.7-0.20210524175448-3115f89c4b99/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -455,13 +430,12 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg= -golang.zx2c4.com/wireguard v0.0.0-20210510202332-9844c74f67ec/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg= -golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2 h1:wfOOSvHgIzTZ9h5Vb6yUFZNn7uf3bT7PeYsHOO7tYDM= -golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8= -golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5 h1:LpEwXnbN4q2EIPkqbG9KHBUrducJYDOOdL+eMcJAlFo= -golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5/go.mod h1:+1XihzyZUBJcSc5WO9SwNA7v26puQwOEDwanaxfNXPQ= -golang.zx2c4.com/wireguard/windows v0.3.14 h1:5yIDYyrQyGkLqV+tzY4ilMNeIvQeMXAz0glZz9u179A= -golang.zx2c4.com/wireguard/windows v0.3.14/go.mod h1:3P4IEAsb+BjlKZmpUXgy74c0iX9AVwwr3WcVJ8nPgME= +golang.zx2c4.com/wireguard v0.0.0-20210805125648-3957e9b9dd19 h1:ab2jcw2W91Rz07eHAb8Lic7sFQKO0NhBftjv6m/gL/0= +golang.zx2c4.com/wireguard v0.0.0-20210805125648-3957e9b9dd19/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c h1:ADNrRDI5NR23/TUCnEmlLZLt4u9DnZ2nwRkPrAcFvto= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c/go.mod h1:+1XihzyZUBJcSc5WO9SwNA7v26puQwOEDwanaxfNXPQ= +golang.zx2c4.com/wireguard/windows v0.4.5 h1:btpw+5IM8UrSl5SILCODt1bXTM2qYpcaYArM6wDlwHA= +golang.zx2c4.com/wireguard/windows v0.4.5/go.mod h1:LdS2bRTWu//RpztraGz5ZkPZul60cCbmgtLTPSKrS50= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -470,7 +444,6 @@ google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -507,8 +480,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= diff --git a/iface/iface.go b/iface/iface.go index 4f54cf657..e6c9a3bcd 100644 --- a/iface/iface.go +++ b/iface/iface.go @@ -74,6 +74,30 @@ func configureDevice(iface string, config wgtypes.Config) error { return wg.ConfigureDevice(iface, config) } +// Exists checks whether specified Wireguard device exists or not +func Exists(iface string) (*bool, error) { + wg, err := wgctrl.New() + if err != nil { + return nil, err + } + defer wg.Close() + + devices, err := wg.Devices() + if err != nil { + return nil, err + } + + var exists bool + for _, d := range devices { + if d.Name == iface { + exists = true + return &exists, nil + } + } + exists = false + return &exists, nil +} + // Configure configures a Wireguard interface // The interface must exist before calling this method (e.g. call interface.Create() before) func Configure(iface string, privateKey string) error { diff --git a/iface/iface_linux.go b/iface/iface_linux.go index 05116380c..71a706c12 100644 --- a/iface/iface_linux.go +++ b/iface/iface_linux.go @@ -44,7 +44,7 @@ func CreateWithKernel(iface string, address string) error { } // todo do a discovery - log.Debugf("setting MTU: %s", iface) + log.Debugf("setting MTU: %d interface: %s", defaultMTU, iface) err = netlink.LinkSetMTU(&link, defaultMTU) if err != nil { log.Errorf("error setting MTU on interface: %s", iface) diff --git a/iface/ifacename.go b/iface/ifacename.go new file mode 100644 index 000000000..3fcb0e60e --- /dev/null +++ b/iface/ifacename.go @@ -0,0 +1,6 @@ +// +build linux windows + +package iface + +// WgInterfaceDefault is a default interface name of Wiretrustee +const WgInterfaceDefault = "wt0" diff --git a/iface/ifacename_darwin.go b/iface/ifacename_darwin.go new file mode 100644 index 000000000..5f25ad29e --- /dev/null +++ b/iface/ifacename_darwin.go @@ -0,0 +1,6 @@ +// +build darwin + +package iface + +// WgInterfaceDefault is a default interface name of Wiretrustee +const WgInterfaceDefault = "utun100" diff --git a/management/client/client.go b/management/client/client.go new file mode 100644 index 000000000..10e1de8c9 --- /dev/null +++ b/management/client/client.go @@ -0,0 +1,210 @@ +package client + +import ( + "context" + "crypto/tls" + "github.com/cenkalti/backoff/v4" + log "github.com/sirupsen/logrus" + "github.com/wiretrustee/wiretrustee/encryption" + "github.com/wiretrustee/wiretrustee/management/proto" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/keepalive" + "io" + "time" +) + +type Client struct { + key wgtypes.Key + realClient proto.ManagementServiceClient + ctx context.Context + conn *grpc.ClientConn +} + +// NewClient creates a new client to Management service +func NewClient(ctx context.Context, addr string, outPrivateKey wgtypes.Key, tlsEnabled bool) (*Client, error) { + + transportOption := grpc.WithInsecure() + + if tlsEnabled { + transportOption = grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})) + } + + conn, err := grpc.DialContext( + ctx, + addr, + transportOption, + grpc.WithBlock(), + grpc.WithKeepaliveParams(keepalive.ClientParameters{ + Time: 3 * time.Second, + Timeout: 2 * time.Second, + })) + + if err != nil { + log.Errorf("failed creating connection to Management Srvice %v", err) + return nil, err + } + + realClient := proto.NewManagementServiceClient(conn) + + return &Client{ + key: outPrivateKey, + realClient: realClient, + ctx: ctx, + conn: conn, + }, nil +} + +// Close closes connection to the Management Service +func (c *Client) Close() error { + return c.conn.Close() +} + +// Sync wraps the real client's Sync endpoint call and takes care of retries and encryption/decryption of messages +func (c *Client) Sync(msgHandler func(msg *proto.SyncResponse) error) { + + go func() { + + var backOff = &backoff.ExponentialBackOff{ + InitialInterval: 800 * time.Millisecond, + RandomizationFactor: backoff.DefaultRandomizationFactor, + Multiplier: backoff.DefaultMultiplier, + MaxInterval: 3 * time.Second, + MaxElapsedTime: time.Duration(0), //never stop retrying + Stop: backoff.Stop, + Clock: backoff.SystemClock, + } + + operation := func() error { + + // todo we already have it since we did the Login, maybe cache it locally? + serverPubKey, err := c.GetServerPublicKey() + if err != nil { + log.Errorf("failed getting Management Service public key: %s", err) + return err + } + + stream, err := c.connectToStream(*serverPubKey) + if err != nil { + log.Errorf("failed to open Management Service stream: %s", err) + return err + } + + log.Infof("connected to the Management Service Stream") + + // blocking until error + err = c.receiveEvents(stream, *serverPubKey, msgHandler) + if err != nil { + return err + } + backOff.Reset() + return nil + } + + err := backoff.Retry(operation, backOff) + if err != nil { + log.Errorf("failed communicating with Management Service %s ", err) + return + } + }() +} + +func (c *Client) connectToStream(serverPubKey wgtypes.Key) (proto.ManagementService_SyncClient, error) { + req := &proto.SyncRequest{} + + myPrivateKey := c.key + myPublicKey := myPrivateKey.PublicKey() + + encryptedReq, err := encryption.EncryptMessage(serverPubKey, myPrivateKey, req) + if err != nil { + log.Errorf("failed encrypting message: %s", err) + return nil, err + } + + syncReq := &proto.EncryptedMessage{WgPubKey: myPublicKey.String(), Body: encryptedReq} + return c.realClient.Sync(c.ctx, syncReq) +} + +func (c *Client) receiveEvents(stream proto.ManagementService_SyncClient, serverPubKey wgtypes.Key, msgHandler func(msg *proto.SyncResponse) error) error { + for { + update, err := stream.Recv() + if err == io.EOF { + log.Errorf("managment stream was closed: %s", err) + return err + } + if err != nil { + log.Errorf("disconnected from Management Service syn stream: %v", err) + return err + } + + log.Debugf("got an update message from Management Service") + decryptedResp := &proto.SyncResponse{} + err = encryption.DecryptMessage(serverPubKey, c.key, update.Body, decryptedResp) + if err != nil { + log.Errorf("failed decrypting update message from Management Service: %s", err) + return err + } + + err = msgHandler(decryptedResp) + if err != nil { + log.Errorf("failed handling an update message received from Management Service %v", err.Error()) + return err + } + } +} + +// GetServerPublicKey returns server Wireguard public key (used later for encrypting messages sent to the server) +func (c *Client) GetServerPublicKey() (*wgtypes.Key, error) { + mgmCtx, cancel := context.WithTimeout(c.ctx, 5*time.Second) //todo make a general setting + defer cancel() + resp, err := c.realClient.GetServerKey(mgmCtx, &proto.Empty{}) + if err != nil { + return nil, err + } + + serverKey, err := wgtypes.ParseKey(resp.Key) + if err != nil { + return nil, err + } + + return &serverKey, nil +} + +func (c *Client) login(serverKey wgtypes.Key, req *proto.LoginRequest) (*proto.LoginResponse, error) { + loginReq, err := encryption.EncryptMessage(serverKey, c.key, req) + if err != nil { + log.Errorf("failed to encrypt message: %s", err) + return nil, err + } + mgmCtx, cancel := context.WithTimeout(c.ctx, 5*time.Second) //todo make a general setting + defer cancel() + resp, err := c.realClient.Login(mgmCtx, &proto.EncryptedMessage{ + WgPubKey: c.key.PublicKey().String(), + Body: loginReq, + }) + + if err != nil { + return nil, err + } + + loginResp := &proto.LoginResponse{} + err = encryption.DecryptMessage(serverKey, c.key, resp.Body, loginResp) + if err != nil { + log.Errorf("failed to decrypt registration message: %s", err) + return nil, err + } + + return loginResp, nil +} + +// Register registers peer on Management Server. It actually calls a Login endpoint with a provided setup key +// Takes care of encrypting and decrypting messages. +func (c *Client) Register(serverKey wgtypes.Key, setupKey string) (*proto.LoginResponse, error) { + return c.login(serverKey, &proto.LoginRequest{SetupKey: setupKey}) +} + +// Login attempts login to Management Server. Takes care of encrypting and decrypting messages. +func (c *Client) Login(serverKey wgtypes.Key) (*proto.LoginResponse, error) { + return c.login(serverKey, &proto.LoginRequest{}) +} diff --git a/management/proto/management.pb.go b/management/proto/management.pb.go index 3dc0edd23..8bc65ed4a 100644 --- a/management/proto/management.pb.go +++ b/management/proto/management.pb.go @@ -236,19 +236,17 @@ func (x *SyncResponse) GetRemotePeers() []*RemotePeerConfig { return nil } -type RegisterPeerRequest struct { +type LoginRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Wireguard public key - Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - // Pre-authorized setup key - SetupKey string `protobuf:"bytes,2,opt,name=setupKey,proto3" json:"setupKey,omitempty"` + // Pre-authorized setup key (can be empty) + SetupKey string `protobuf:"bytes,1,opt,name=setupKey,proto3" json:"setupKey,omitempty"` } -func (x *RegisterPeerRequest) Reset() { - *x = RegisterPeerRequest{} +func (x *LoginRequest) Reset() { + *x = LoginRequest{} if protoimpl.UnsafeEnabled { mi := &file_management_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -256,13 +254,13 @@ func (x *RegisterPeerRequest) Reset() { } } -func (x *RegisterPeerRequest) String() string { +func (x *LoginRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*RegisterPeerRequest) ProtoMessage() {} +func (*LoginRequest) ProtoMessage() {} -func (x *RegisterPeerRequest) ProtoReflect() protoreflect.Message { +func (x *LoginRequest) ProtoReflect() protoreflect.Message { mi := &file_management_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -274,33 +272,31 @@ func (x *RegisterPeerRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use RegisterPeerRequest.ProtoReflect.Descriptor instead. -func (*RegisterPeerRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use LoginRequest.ProtoReflect.Descriptor instead. +func (*LoginRequest) Descriptor() ([]byte, []int) { return file_management_proto_rawDescGZIP(), []int{3} } -func (x *RegisterPeerRequest) GetKey() string { - if x != nil { - return x.Key - } - return "" -} - -func (x *RegisterPeerRequest) GetSetupKey() string { +func (x *LoginRequest) GetSetupKey() string { if x != nil { return x.SetupKey } return "" } -type RegisterPeerResponse struct { +type LoginResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + // Global config + WiretrusteeConfig *WiretrusteeConfig `protobuf:"bytes,1,opt,name=wiretrusteeConfig,proto3" json:"wiretrusteeConfig,omitempty"` + // Peer local config + PeerConfig *PeerConfig `protobuf:"bytes,2,opt,name=peerConfig,proto3" json:"peerConfig,omitempty"` } -func (x *RegisterPeerResponse) Reset() { - *x = RegisterPeerResponse{} +func (x *LoginResponse) Reset() { + *x = LoginResponse{} if protoimpl.UnsafeEnabled { mi := &file_management_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -308,13 +304,13 @@ func (x *RegisterPeerResponse) Reset() { } } -func (x *RegisterPeerResponse) String() string { +func (x *LoginResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*RegisterPeerResponse) ProtoMessage() {} +func (*LoginResponse) ProtoMessage() {} -func (x *RegisterPeerResponse) ProtoReflect() protoreflect.Message { +func (x *LoginResponse) ProtoReflect() protoreflect.Message { mi := &file_management_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -326,11 +322,25 @@ func (x *RegisterPeerResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use RegisterPeerResponse.ProtoReflect.Descriptor instead. -func (*RegisterPeerResponse) Descriptor() ([]byte, []int) { +// Deprecated: Use LoginResponse.ProtoReflect.Descriptor instead. +func (*LoginResponse) Descriptor() ([]byte, []int) { return file_management_proto_rawDescGZIP(), []int{4} } +func (x *LoginResponse) GetWiretrusteeConfig() *WiretrusteeConfig { + if x != nil { + return x.WiretrusteeConfig + } + return nil +} + +func (x *LoginResponse) GetPeerConfig() *PeerConfig { + if x != nil { + return x.PeerConfig + } + return nil +} + type ServerKeyResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -758,76 +768,82 @@ 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, 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, + 0x6f, 0x74, 0x65, 0x50, 0x65, 0x65, 0x72, 0x73, 0x22, 0x2a, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x75, + 0x70, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x74, 0x75, + 0x70, 0x4b, 0x65, 0x79, 0x22, 0x94, 0x01, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 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, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x52, 0x11, 0x77, 0x69, 0x72, 0x65, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x0a, 0x70, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 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, 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, + 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, 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, 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, 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, 0x9b, 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, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -845,44 +861,46 @@ func file_management_proto_rawDescGZIP() []byte { var file_management_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_management_proto_msgTypes = make([]protoimpl.MessageInfo, 12) var file_management_proto_goTypes = []interface{}{ - (HostConfig_Protocol)(0), // 0: management.HostConfig.Protocol - (*EncryptedMessage)(nil), // 1: management.EncryptedMessage - (*SyncRequest)(nil), // 2: management.SyncRequest - (*SyncResponse)(nil), // 3: management.SyncResponse - (*RegisterPeerRequest)(nil), // 4: management.RegisterPeerRequest - (*RegisterPeerResponse)(nil), // 5: management.RegisterPeerResponse - (*ServerKeyResponse)(nil), // 6: management.ServerKeyResponse - (*Empty)(nil), // 7: management.Empty - (*WiretrusteeConfig)(nil), // 8: management.WiretrusteeConfig - (*HostConfig)(nil), // 9: management.HostConfig - (*ProtectedHostConfig)(nil), // 10: management.ProtectedHostConfig - (*PeerConfig)(nil), // 11: management.PeerConfig - (*RemotePeerConfig)(nil), // 12: management.RemotePeerConfig - (*timestamp.Timestamp)(nil), // 13: google.protobuf.Timestamp + (HostConfig_Protocol)(0), // 0: management.HostConfig.Protocol + (*EncryptedMessage)(nil), // 1: management.EncryptedMessage + (*SyncRequest)(nil), // 2: management.SyncRequest + (*SyncResponse)(nil), // 3: management.SyncResponse + (*LoginRequest)(nil), // 4: management.LoginRequest + (*LoginResponse)(nil), // 5: management.LoginResponse + (*ServerKeyResponse)(nil), // 6: management.ServerKeyResponse + (*Empty)(nil), // 7: management.Empty + (*WiretrusteeConfig)(nil), // 8: management.WiretrusteeConfig + (*HostConfig)(nil), // 9: management.HostConfig + (*ProtectedHostConfig)(nil), // 10: management.ProtectedHostConfig + (*PeerConfig)(nil), // 11: management.PeerConfig + (*RemotePeerConfig)(nil), // 12: management.RemotePeerConfig + (*timestamp.Timestamp)(nil), // 13: google.protobuf.Timestamp } var file_management_proto_depIdxs = []int32{ 8, // 0: management.SyncResponse.wiretrusteeConfig:type_name -> management.WiretrusteeConfig 11, // 1: management.SyncResponse.peerConfig:type_name -> management.PeerConfig 12, // 2: management.SyncResponse.remotePeers:type_name -> management.RemotePeerConfig - 13, // 3: management.ServerKeyResponse.expiresAt:type_name -> google.protobuf.Timestamp - 9, // 4: management.WiretrusteeConfig.stuns:type_name -> management.HostConfig - 10, // 5: management.WiretrusteeConfig.turns:type_name -> management.ProtectedHostConfig - 9, // 6: management.WiretrusteeConfig.signal:type_name -> management.HostConfig - 0, // 7: management.HostConfig.protocol:type_name -> management.HostConfig.Protocol - 9, // 8: management.ProtectedHostConfig.hostConfig:type_name -> management.HostConfig - 4, // 9: management.ManagementService.RegisterPeer:input_type -> management.RegisterPeerRequest - 1, // 10: management.ManagementService.Sync:input_type -> management.EncryptedMessage - 7, // 11: management.ManagementService.GetServerKey:input_type -> management.Empty - 7, // 12: management.ManagementService.isHealthy:input_type -> management.Empty - 5, // 13: management.ManagementService.RegisterPeer:output_type -> management.RegisterPeerResponse - 1, // 14: management.ManagementService.Sync:output_type -> management.EncryptedMessage - 6, // 15: management.ManagementService.GetServerKey:output_type -> management.ServerKeyResponse - 7, // 16: management.ManagementService.isHealthy:output_type -> management.Empty - 13, // [13:17] is the sub-list for method output_type - 9, // [9:13] is the sub-list for method input_type - 9, // [9:9] is the sub-list for extension type_name - 9, // [9:9] is the sub-list for extension extendee - 0, // [0:9] is the sub-list for field type_name + 8, // 3: management.LoginResponse.wiretrusteeConfig:type_name -> management.WiretrusteeConfig + 11, // 4: management.LoginResponse.peerConfig:type_name -> management.PeerConfig + 13, // 5: management.ServerKeyResponse.expiresAt:type_name -> google.protobuf.Timestamp + 9, // 6: management.WiretrusteeConfig.stuns:type_name -> management.HostConfig + 10, // 7: management.WiretrusteeConfig.turns:type_name -> management.ProtectedHostConfig + 9, // 8: management.WiretrusteeConfig.signal:type_name -> management.HostConfig + 0, // 9: management.HostConfig.protocol:type_name -> management.HostConfig.Protocol + 9, // 10: management.ProtectedHostConfig.hostConfig:type_name -> management.HostConfig + 1, // 11: management.ManagementService.Login:input_type -> management.EncryptedMessage + 1, // 12: management.ManagementService.Sync:input_type -> management.EncryptedMessage + 7, // 13: management.ManagementService.GetServerKey:input_type -> management.Empty + 7, // 14: management.ManagementService.isHealthy:input_type -> management.Empty + 1, // 15: management.ManagementService.Login:output_type -> management.EncryptedMessage + 1, // 16: management.ManagementService.Sync:output_type -> management.EncryptedMessage + 6, // 17: management.ManagementService.GetServerKey:output_type -> management.ServerKeyResponse + 7, // 18: management.ManagementService.isHealthy:output_type -> management.Empty + 15, // [15:19] is the sub-list for method output_type + 11, // [11:15] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name } func init() { file_management_proto_init() } @@ -928,7 +946,7 @@ func file_management_proto_init() { } } file_management_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterPeerRequest); i { + switch v := v.(*LoginRequest); i { case 0: return &v.state case 1: @@ -940,7 +958,7 @@ func file_management_proto_init() { } } file_management_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterPeerResponse); i { + switch v := v.(*LoginResponse); i { case 0: return &v.state case 1: diff --git a/management/proto/management.proto b/management/proto/management.proto index df7ef844f..0739abefc 100644 --- a/management/proto/management.proto +++ b/management/proto/management.proto @@ -8,7 +8,8 @@ package management; service ManagementService { - rpc RegisterPeer(RegisterPeerRequest) returns (RegisterPeerResponse) {} + // Login logs in peer. In case server returns codes.PermissionDenied this endpoint can be used to register Peer providing LoginRequest.setupKey + 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 @@ -43,15 +44,17 @@ message SyncResponse { repeated RemotePeerConfig remotePeers = 3; } -message RegisterPeerRequest { - // Wireguard public key - string key = 1; - - // Pre-authorized setup key - string setupKey = 2; +message LoginRequest { + // Pre-authorized setup key (can be empty) + string setupKey = 1; } -message RegisterPeerResponse {} +message LoginResponse { + // Global config + WiretrusteeConfig wiretrusteeConfig = 1; + // Peer local config + PeerConfig peerConfig = 2; +} message ServerKeyResponse { // Server's Wireguard public key diff --git a/management/proto/management_grpc.pb.go b/management/proto/management_grpc.pb.go index 975ce4143..57e6f209a 100644 --- a/management/proto/management_grpc.pb.go +++ b/management/proto/management_grpc.pb.go @@ -18,7 +18,8 @@ const _ = grpc.SupportPackageIsVersion7 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type ManagementServiceClient interface { - RegisterPeer(ctx context.Context, in *RegisterPeerRequest, opts ...grpc.CallOption) (*RegisterPeerResponse, error) + // Login logs in peer. In case server returns codes.PermissionDenied this endpoint can be used to register Peer providing LoginRequest.setupKey + Login(ctx context.Context, in *EncryptedMessage, opts ...grpc.CallOption) (*EncryptedMessage, error) // 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 @@ -38,9 +39,9 @@ func NewManagementServiceClient(cc grpc.ClientConnInterface) ManagementServiceCl return &managementServiceClient{cc} } -func (c *managementServiceClient) RegisterPeer(ctx context.Context, in *RegisterPeerRequest, opts ...grpc.CallOption) (*RegisterPeerResponse, error) { - out := new(RegisterPeerResponse) - err := c.cc.Invoke(ctx, "/management.ManagementService/RegisterPeer", in, out, opts...) +func (c *managementServiceClient) Login(ctx context.Context, in *EncryptedMessage, opts ...grpc.CallOption) (*EncryptedMessage, error) { + out := new(EncryptedMessage) + err := c.cc.Invoke(ctx, "/management.ManagementService/Login", in, out, opts...) if err != nil { return nil, err } @@ -101,7 +102,8 @@ func (c *managementServiceClient) IsHealthy(ctx context.Context, in *Empty, opts // All implementations must embed UnimplementedManagementServiceServer // for forward compatibility type ManagementServiceServer interface { - RegisterPeer(context.Context, *RegisterPeerRequest) (*RegisterPeerResponse, error) + // Login logs in peer. In case server returns codes.PermissionDenied this endpoint can be used to register Peer providing LoginRequest.setupKey + Login(context.Context, *EncryptedMessage) (*EncryptedMessage, error) // 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 @@ -118,8 +120,8 @@ type ManagementServiceServer interface { type UnimplementedManagementServiceServer struct { } -func (UnimplementedManagementServiceServer) RegisterPeer(context.Context, *RegisterPeerRequest) (*RegisterPeerResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method RegisterPeer not implemented") +func (UnimplementedManagementServiceServer) Login(context.Context, *EncryptedMessage) (*EncryptedMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method Login not implemented") } func (UnimplementedManagementServiceServer) Sync(*EncryptedMessage, ManagementService_SyncServer) error { return status.Errorf(codes.Unimplemented, "method Sync not implemented") @@ -143,20 +145,20 @@ func RegisterManagementServiceServer(s grpc.ServiceRegistrar, srv ManagementServ s.RegisterService(&ManagementService_ServiceDesc, srv) } -func _ManagementService_RegisterPeer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(RegisterPeerRequest) +func _ManagementService_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EncryptedMessage) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(ManagementServiceServer).RegisterPeer(ctx, in) + return srv.(ManagementServiceServer).Login(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/management.ManagementService/RegisterPeer", + FullMethod: "/management.ManagementService/Login", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ManagementServiceServer).RegisterPeer(ctx, req.(*RegisterPeerRequest)) + return srv.(ManagementServiceServer).Login(ctx, req.(*EncryptedMessage)) } return interceptor(ctx, in, info, handler) } @@ -226,8 +228,8 @@ var ManagementService_ServiceDesc = grpc.ServiceDesc{ HandlerType: (*ManagementServiceServer)(nil), Methods: []grpc.MethodDesc{ { - MethodName: "RegisterPeer", - Handler: _ManagementService_RegisterPeer_Handler, + MethodName: "Login", + Handler: _ManagementService_Login_Handler, }, { MethodName: "GetServerKey", diff --git a/management/server/account.go b/management/server/account.go index 2ce97ba16..d48d35fe5 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -55,7 +55,7 @@ func (manager *AccountManager) GetPeer(peerKey string) (*Peer, error) { peer, err := manager.Store.GetPeer(peerKey) if err != nil { - return nil, status.Errorf(codes.NotFound, "provided peer key doesn't exists %s", peerKey) + return nil, err } return peer, nil diff --git a/management/server/file_store.go b/management/server/file_store.go index 10c1606c1..1ca56a7d1 100644 --- a/management/server/file_store.go +++ b/management/server/file_store.go @@ -70,7 +70,7 @@ func restore(file string) (*FileStore, error) { store.SetupKeyId2AccountId[strings.ToLower(setupKeyId)] = accountId } for _, peer := range account.Peers { - store.PeerKeyId2AccountId[strings.ToLower(peer.Key)] = accountId + store.PeerKeyId2AccountId[peer.Key] = accountId } } @@ -90,7 +90,7 @@ func (s *FileStore) GetPeer(peerKey string) (*Peer, error) { accountId, accountIdFound := s.PeerKeyId2AccountId[peerKey] if !accountIdFound { - return nil, status.Errorf(codes.Internal, "account not found") + return nil, status.Errorf(codes.NotFound, "peer not found") } account, err := s.GetAccount(accountId) diff --git a/management/server/grpc/server.go b/management/server/grpc/server.go index 75c7f2a7b..54a1d9dce 100644 --- a/management/server/grpc/server.go +++ b/management/server/grpc/server.go @@ -77,7 +77,7 @@ func (s *Server) Sync(req *proto.EncryptedMessage, srv proto.ManagementService_S 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()) + return status.Errorf(codes.PermissionDenied, "provided peer with the key wgPubKey %s is not registered", peerKey.String()) } syncReq := &proto.SyncRequest{} @@ -126,23 +126,18 @@ func (s *Server) Sync(req *proto.EncryptedMessage, srv proto.ManagementService_S } } -// RegisterPeer adds a peer to the Store. Returns 404 in case the provided setup key doesn't exist -func (s *Server) RegisterPeer(ctx context.Context, req *proto.RegisterPeerRequest) (*proto.RegisterPeerResponse, error) { - - log.Debugf("RegisterPeer request from peer %s", req.Key) - +func (s *Server) registerPeer(peerKey wgtypes.Key, setupKey string) (*server.Peer, error) { s.channelsMux.Lock() defer s.channelsMux.Unlock() - peer, err := s.accountManager.AddPeer(req.SetupKey, req.Key) + peer, err := s.accountManager.AddPeer(setupKey, peerKey.String()) if err != nil { - return &proto.RegisterPeerResponse{}, status.Errorf(codes.NotFound, "provided setup key doesn't exists") + return nil, status.Errorf(codes.NotFound, "provided setup key doesn't exists") } peers, err := s.accountManager.GetPeersForAPeer(peer.Key) if err != nil { - //todo return a proper error - return nil, err + return nil, status.Error(codes.Internal, "internal server error") } // notify other peers of our registration @@ -160,7 +155,63 @@ func (s *Server) RegisterPeer(ctx context.Context, req *proto.RegisterPeerReques } } - return &proto.RegisterPeerResponse{}, nil + return peer, nil +} + +// Login endpoint first checks whether peer is registered under any account +// In case it is, the login is successful +// In case it isn't, the endpoint checks whether setup key is provided within the request and tries to register a peer. +// In case of the successful registration login is also successful +func (s *Server) Login(ctx context.Context, req *proto.EncryptedMessage) (*proto.EncryptedMessage, error) { + + log.Debugf("Login request from peer %s", req.WgPubKey) + + peerKey, err := wgtypes.ParseKey(req.GetWgPubKey()) + if err != nil { + log.Warnf("error while parsing peer's Wireguard public key %s on Sync request.", req.WgPubKey) + return nil, status.Errorf(codes.InvalidArgument, "provided wgPubKey %s is invalid", req.WgPubKey) + } + + peer, err := s.accountManager.GetPeer(peerKey.String()) + if err != nil { + if errStatus, ok := status.FromError(err); ok && errStatus.Code() == codes.NotFound { + //peer doesn't exist -> check if setup key was provided + loginReq := &proto.LoginRequest{} + err = encryption.DecryptMessage(peerKey, s.wgKey, req.Body, loginReq) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "invalid request message") + } + + if loginReq.GetSetupKey() == "" { + //absent setup key -> permission denied + return nil, status.Errorf(codes.PermissionDenied, "provided peer with the key wgPubKey %s is not registered", peerKey.String()) + } + + //setup key is present -> try normal registration flow + peer, err = s.registerPeer(peerKey, loginReq.GetSetupKey()) + if err != nil { + return nil, err + } + + } else { + return nil, status.Error(codes.Internal, "internal server error") + } + } + + // if peer has reached this point then it has logged in + loginResp := &proto.LoginResponse{ + WiretrusteeConfig: toWiretrusteeConfig(s.config), + PeerConfig: toPeerConfig(peer), + } + encryptedResp, err := encryption.EncryptMessage(peerKey, s.wgKey, loginResp) + if err != nil { + return nil, status.Errorf(codes.Internal, "failed logging in peer") + } + + return &proto.EncryptedMessage{ + WgPubKey: s.wgKey.PublicKey().String(), + Body: encryptedResp, + }, nil } func toResponseProto(configProto server.Protocol) proto.HostConfig_Protocol { @@ -181,7 +232,7 @@ func toResponseProto(configProto server.Protocol) proto.HostConfig_Protocol { } } -func toSyncResponse(config *server.Config, peer *server.Peer, peers []*server.Peer) *proto.SyncResponse { +func toWiretrusteeConfig(config *server.Config) *proto.WiretrusteeConfig { var stuns []*proto.HostConfig for _, stun := range config.Stuns { @@ -202,7 +253,7 @@ func toSyncResponse(config *server.Config, peer *server.Peer, peers []*server.Pe }) } - wtConfig := &proto.WiretrusteeConfig{ + return &proto.WiretrusteeConfig{ Stuns: stuns, Turns: turns, Signal: &proto.HostConfig{ @@ -210,10 +261,19 @@ func toSyncResponse(config *server.Config, peer *server.Peer, peers []*server.Pe Protocol: toResponseProto(config.Signal.Proto), }, } +} - pConfig := &proto.PeerConfig{ - Address: peer.IP.String(), +func toPeerConfig(peer *server.Peer) *proto.PeerConfig { + return &proto.PeerConfig{ + Address: peer.IP.String() + "/24", //todo make it explicit } +} + +func toSyncResponse(config *server.Config, peer *server.Peer, peers []*server.Peer) *proto.SyncResponse { + + wtConfig := toWiretrusteeConfig(config) + + pConfig := toPeerConfig(peer) remotePeers := make([]*proto.RemotePeerConfig, 0, len(peers)) for _, rPeer := range peers { diff --git a/management/server/management_test.go b/management/server/management_test.go index 144db1f1a..f3ebddf81 100644 --- a/management/server/management_test.go +++ b/management/server/management_test.go @@ -92,7 +92,7 @@ var _ = Describe("Management service", func() { Context("when there is a new peer registered", func() { Specify("a proper configuration is returned", func() { key, _ := wgtypes.GenerateKey() - registerPeerWithValidSetupKey(key, client) + loginPeerWithValidSetupKey(serverPubKey, key, client) encryptedBytes, err := encryption.EncryptMessage(serverPubKey, key, &mgmtProto.SyncRequest{}) Expect(err).NotTo(HaveOccurred()) @@ -111,7 +111,7 @@ var _ = Describe("Management service", func() { err = encryption.DecryptMessage(serverPubKey, key, encryptedResponse.Body, resp) Expect(err).NotTo(HaveOccurred()) - Expect(resp.PeerConfig.Address).To(BeEquivalentTo("100.64.0.1")) + Expect(resp.PeerConfig.Address).To(BeEquivalentTo("100.64.0.1/24")) expectedSignalConfig := &mgmtProto.HostConfig{ Uri: "signal.wiretrustee.com:10000", @@ -142,9 +142,9 @@ var _ = Describe("Management service", func() { key, _ := wgtypes.GenerateKey() key1, _ := wgtypes.GenerateKey() key2, _ := wgtypes.GenerateKey() - registerPeerWithValidSetupKey(key, client) - registerPeerWithValidSetupKey(key1, client) - registerPeerWithValidSetupKey(key2, client) + loginPeerWithValidSetupKey(serverPubKey, key, client) + loginPeerWithValidSetupKey(serverPubKey, key1, client) + loginPeerWithValidSetupKey(serverPubKey, key2, client) messageBytes, err := pb.Marshal(&mgmtProto.SyncRequest{}) Expect(err).NotTo(HaveOccurred()) @@ -178,7 +178,7 @@ var _ = Describe("Management service", func() { Specify("an update is returned", func() { // register only a single peer key, _ := wgtypes.GenerateKey() - registerPeerWithValidSetupKey(key, client) + loginPeerWithValidSetupKey(serverPubKey, key, client) messageBytes, err := pb.Marshal(&mgmtProto.SyncRequest{}) Expect(err).NotTo(HaveOccurred()) @@ -218,7 +218,7 @@ var _ = Describe("Management service", func() { // register a new peer key1, _ := wgtypes.GenerateKey() - registerPeerWithValidSetupKey(key1, client) + loginPeerWithValidSetupKey(serverPubKey, key1, client) wg.Wait() @@ -247,15 +247,18 @@ var _ = Describe("Management service", func() { }) }) - Context("when calling RegisterPeer endpoint", func() { + Context("when calling Login endpoint", func() { Context("with an invalid setup key", func() { Specify("an error is returned", func() { key, _ := wgtypes.GenerateKey() - resp, err := client.RegisterPeer(context.TODO(), &mgmtProto.RegisterPeerRequest{ - Key: key.PublicKey().String(), - SetupKey: InvalidSetupKey, + message, err := encryption.EncryptMessage(serverPubKey, key, &mgmtProto.LoginRequest{SetupKey: "invalid setup key"}) + Expect(err).NotTo(HaveOccurred()) + + resp, err := client.Login(context.TODO(), &mgmtProto.EncryptedMessage{ + WgPubKey: key.PublicKey().String(), + Body: message, }) Expect(err).To(HaveOccurred()) @@ -268,12 +271,56 @@ var _ = Describe("Management service", func() { It("a non error result is returned", func() { key, _ := wgtypes.GenerateKey() - resp := registerPeerWithValidSetupKey(key, client) + resp := loginPeerWithValidSetupKey(serverPubKey, key, client) Expect(resp).ToNot(BeNil()) }) }) + + Context("with a registered peer", func() { + It("a non error result is returned", func() { + + key, _ := wgtypes.GenerateKey() + regResp := loginPeerWithValidSetupKey(serverPubKey, key, client) + Expect(regResp).NotTo(BeNil()) + + // just login without registration + message, err := encryption.EncryptMessage(serverPubKey, key, &mgmtProto.LoginRequest{}) + Expect(err).NotTo(HaveOccurred()) + loginResp, err := client.Login(context.TODO(), &mgmtProto.EncryptedMessage{ + WgPubKey: key.PublicKey().String(), + Body: message, + }) + + Expect(err).NotTo(HaveOccurred()) + + decryptedResp := &mgmtProto.LoginResponse{} + err = encryption.DecryptMessage(serverPubKey, key, loginResp.Body, decryptedResp) + Expect(err).NotTo(HaveOccurred()) + + 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(decryptedResp.GetWiretrusteeConfig().Signal).To(BeEquivalentTo(expectedSignalConfig)) + Expect(decryptedResp.GetWiretrusteeConfig().Stuns).To(ConsistOf(expectedStunsConfig)) + Expect(decryptedResp.GetWiretrusteeConfig().Turns).To(ConsistOf(expectedTurnsConfig)) + }) + }) }) Context("when there are 50 peers registered under one account", func() { @@ -286,7 +333,7 @@ var _ = Describe("Management service", func() { var peers []wgtypes.Key for i := 0; i < initialPeers; i++ { key, _ := wgtypes.GenerateKey() - registerPeerWithValidSetupKey(key, client) + loginPeerWithValidSetupKey(serverPubKey, key, client) peers = append(peers, key) } @@ -331,7 +378,7 @@ var _ = Describe("Management service", func() { time.Sleep(1 * time.Second) for i := 0; i < additionalPeers; i++ { key, _ := wgtypes.GenerateKey() - registerPeerWithValidSetupKey(key, client) + loginPeerWithValidSetupKey(serverPubKey, key, client) rand.Seed(time.Now().UnixNano()) n := rand.Intn(500) time.Sleep(time.Duration(n) * time.Millisecond) @@ -357,7 +404,7 @@ var _ = Describe("Management service", func() { for i := 0; i < initialPeers; i++ { go func() { key, _ := wgtypes.GenerateKey() - registerPeerWithValidSetupKey(key, client) + loginPeerWithValidSetupKey(serverPubKey, key, client) encryptedBytes, err := encryption.EncryptMessage(serverPubKey, key, &mgmtProto.SyncRequest{}) Expect(err).NotTo(HaveOccurred()) @@ -395,16 +442,22 @@ var _ = Describe("Management service", func() { }) }) -func registerPeerWithValidSetupKey(key wgtypes.Key, client mgmtProto.ManagementServiceClient) *mgmtProto.RegisterPeerResponse { +func loginPeerWithValidSetupKey(serverPubKey wgtypes.Key, key wgtypes.Key, client mgmtProto.ManagementServiceClient) *mgmtProto.LoginResponse { - resp, err := client.RegisterPeer(context.TODO(), &mgmtProto.RegisterPeerRequest{ - Key: key.PublicKey().String(), - SetupKey: ValidSetupKey, + message, err := encryption.EncryptMessage(serverPubKey, key, &mgmtProto.LoginRequest{SetupKey: ValidSetupKey}) + Expect(err).NotTo(HaveOccurred()) + + resp, err := client.Login(context.TODO(), &mgmtProto.EncryptedMessage{ + WgPubKey: key.PublicKey().String(), + Body: message, }) Expect(err).NotTo(HaveOccurred()) - return resp + loginResp := &mgmtProto.LoginResponse{} + err = encryption.DecryptMessage(serverPubKey, key, resp.Body, loginResp) + Expect(err).NotTo(HaveOccurred()) + return loginResp } diff --git a/signal/cmd/run.go b/signal/cmd/run.go index 7695a97ef..2d04e2551 100644 --- a/signal/cmd/run.go +++ b/signal/cmd/run.go @@ -12,6 +12,7 @@ import ( "google.golang.org/grpc/credentials" "google.golang.org/grpc/keepalive" "net" + "net/http" "os" "time" ) @@ -50,6 +51,14 @@ var ( certManager := encryption.CreateCertManager(signalSSLDir, signalLetsencryptDomain) transportCredentials := credentials.NewTLS(certManager.TLSConfig()) opts = append(opts, grpc.Creds(transportCredentials)) + + listener := certManager.Listener() + log.Infof("http server listening on %s", listener.Addr()) + go func() { + if err := http.Serve(listener, certManager.HTTPHandler(nil)); err != nil { + log.Errorf("failed to serve https server: %v", err) + } + }() } opts = append(opts, signalKaep, signalKasp)