From 6b7d4cf644e8fefd42b306d7b10292d0b18df1da Mon Sep 17 00:00:00 2001 From: Mikhail Bragin Date: Sun, 21 Nov 2021 17:47:19 +0100 Subject: [PATCH] feature: add Wireguard preshared-key support (#160) --- client/cmd/login.go | 8 +------- client/cmd/root.go | 2 ++ client/cmd/up.go | 14 ++++++++++++-- client/internal/config.go | 11 ++++++++--- client/internal/connection.go | 4 +++- client/internal/engine.go | 3 +++ client/internal/wgproxy.go | 35 +++++++++++++++++------------------ iface/iface.go | 3 ++- iface/iface_test.go | 6 +++--- 9 files changed, 51 insertions(+), 35 deletions(-) diff --git a/client/cmd/login.go b/client/cmd/login.go index 53759456b..551dda300 100644 --- a/client/cmd/login.go +++ b/client/cmd/login.go @@ -30,10 +30,9 @@ var ( return err } - config, err := internal.GetConfig(managementURL, configPath) + config, err := internal.GetConfig(managementURL, configPath, preSharedKey) if err != nil { log.Errorf("failed getting config %s %v", configPath, err) - //os.Exit(ExitSetupFailed) return err } @@ -41,7 +40,6 @@ var ( myPrivateKey, err := wgtypes.ParseKey(config.PrivateKey) if err != nil { log.Errorf("failed parsing Wireguard key %s: [%s]", config.PrivateKey, err.Error()) - //os.Exit(ExitSetupFailed) return err } @@ -56,7 +54,6 @@ var ( mgmClient, err := mgm.NewClient(ctx, config.ManagementURL.Host, myPrivateKey, mgmTlsEnabled) if err != nil { log.Errorf("failed connecting to Management Service %s %v", config.ManagementURL.String(), err) - //os.Exit(ExitSetupFailed) return err } log.Debugf("connected to anagement Service %s", config.ManagementURL.String()) @@ -64,21 +61,18 @@ var ( serverKey, err := mgmClient.GetServerPublicKey() if err != nil { log.Errorf("failed while getting Management Service public key: %v", err) - //os.Exit(ExitSetupFailed) return err } _, err = loginPeer(*serverKey, mgmClient, setupKey) if err != nil { log.Errorf("failed logging-in peer on Management Service : %v", err) - //os.Exit(ExitSetupFailed) return err } err = mgmClient.Close() if err != nil { log.Errorf("failed closing Management Service client: %v", err) - //os.Exit(ExitSetupFailed) return err } diff --git a/client/cmd/root.go b/client/cmd/root.go index d1693818f..dc5a87a8c 100644 --- a/client/cmd/root.go +++ b/client/cmd/root.go @@ -21,6 +21,7 @@ var ( logFile string managementURL string setupKey string + preSharedKey string rootCmd = &cobra.Command{ Use: "wiretrustee", Short: "", @@ -53,6 +54,7 @@ func init() { rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "sets Wiretrustee log level") rootCmd.PersistentFlags().StringVar(&logFile, "log-file", defaultLogFile, "sets Wiretrustee log path. If console is specified the the log will be output to stdout") rootCmd.PersistentFlags().StringVar(&setupKey, "setup-key", "", "Setup key obtained from the Management Service Dashboard (used to register peer)") + rootCmd.PersistentFlags().StringVar(&preSharedKey, "preshared-key", "", "Sets Wireguard PreSharedKey property. If set, then only peers that have the same key can communicate.") rootCmd.AddCommand(serviceCmd) rootCmd.AddCommand(upCmd) rootCmd.AddCommand(loginCmd) diff --git a/client/cmd/up.go b/client/cmd/up.go index c63364d75..acb048421 100644 --- a/client/cmd/up.go +++ b/client/cmd/up.go @@ -63,12 +63,22 @@ func createEngineConfig(key wgtypes.Key, config *internal.Config, peerConfig *mg iFaceBlackList[config.IFaceBlackList[i]] = struct{}{} } - return &internal.EngineConfig{ + engineConf := &internal.EngineConfig{ WgIface: config.WgIface, WgAddr: peerConfig.Address, IFaceBlackList: iFaceBlackList, WgPrivateKey: key, - }, nil + } + + if config.PreSharedKey != "" { + preSharedKey, err := wgtypes.ParseKey(config.PreSharedKey) + if err != nil { + return nil, err + } + engineConf.PreSharedKey = &preSharedKey + } + + return engineConf, nil } // connectToSignal creates Signal Service client and established a connection diff --git a/client/internal/config.go b/client/internal/config.go index c6eb353a2..c50260707 100644 --- a/client/internal/config.go +++ b/client/internal/config.go @@ -28,13 +28,14 @@ func init() { type Config struct { // Wireguard private key of local peer PrivateKey string + PreSharedKey string ManagementURL *url.URL 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) { +func createNewConfig(managementURL string, configPath string, preSharedKey string) (*Config, error) { wgKey := generateKey() config := &Config{PrivateKey: wgKey, WgIface: iface.WgInterfaceDefault, IFaceBlackList: []string{}} if managementURL != "" { @@ -47,6 +48,10 @@ func createNewConfig(managementURL string, configPath string) (*Config, error) { config.ManagementURL = managementURLDefault } + if preSharedKey != "" { + config.PreSharedKey = preSharedKey + } + config.IFaceBlackList = []string{iface.WgInterfaceDefault, "tun0"} err := util.WriteJson(configPath, config) @@ -93,11 +98,11 @@ func ReadConfig(managementURL string, configPath string) (*Config, error) { } // GetConfig reads existing config or generates a new one -func GetConfig(managementURL string, configPath string) (*Config, error) { +func GetConfig(managementURL string, configPath string, preSharedKey string) (*Config, error) { if _, err := os.Stat(configPath); os.IsNotExist(err) { log.Infof("generating new config %s", configPath) - return createNewConfig(managementURL, configPath) + return createNewConfig(managementURL, configPath, preSharedKey) } else { return ReadConfig(managementURL, configPath) } diff --git a/client/internal/connection.go b/client/internal/connection.go index 0a2662aed..affa5b8a3 100644 --- a/client/internal/connection.go +++ b/client/internal/connection.go @@ -60,6 +60,8 @@ type ConnConfig struct { // Remote Wireguard public key RemoteWgKey wgtypes.Key + PreSharedKey *wgtypes.Key + StunTurnURLS []*ice.URL iFaceBlackList map[string]struct{} @@ -115,7 +117,7 @@ func NewConnection(config ConnConfig, closeCond: NewCond(), connected: NewCond(), agent: nil, - wgProxy: NewWgProxy(config.WgIface, config.RemoteWgKey.String(), config.WgAllowedIPs, config.WgListenAddr), + wgProxy: NewWgProxy(config.WgIface, config.RemoteWgKey.String(), config.WgAllowedIPs, config.WgListenAddr, config.PreSharedKey), Status: StatusDisconnected, } } diff --git a/client/internal/engine.go b/client/internal/engine.go index ce7421adf..036151c76 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -30,6 +30,8 @@ type EngineConfig struct { WgPrivateKey wgtypes.Key // IFaceBlackList is a list of network interfaces to ignore when discovering connection candidates (ICE related) IFaceBlackList map[string]struct{} + + PreSharedKey *wgtypes.Key } // Engine is a mechanism responsible for reacting on Signal and Management stream events and managing connections to the remote peers. @@ -238,6 +240,7 @@ func (e *Engine) openPeerConnection(wgPort int, myKey wgtypes.Key, peer Peer) (* RemoteWgKey: remoteKey, StunTurnURLS: append(e.STUNs, e.TURNs...), iFaceBlackList: e.config.IFaceBlackList, + PreSharedKey: e.config.PreSharedKey, } signalOffer := func(uFrag string, pwd string) error { diff --git a/client/internal/wgproxy.go b/client/internal/wgproxy.go index 9b2e7e487..037472d40 100644 --- a/client/internal/wgproxy.go +++ b/client/internal/wgproxy.go @@ -4,27 +4,30 @@ import ( ice "github.com/pion/ice/v2" log "github.com/sirupsen/logrus" "github.com/wiretrustee/wiretrustee/iface" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" "net" ) // WgProxy an instance of an instance of the Connection Wireguard Proxy type WgProxy struct { - iface string - remoteKey string - allowedIps string - wgAddr string - close chan struct{} - wgConn net.Conn + iface string + remoteKey string + allowedIps string + wgAddr string + close chan struct{} + wgConn net.Conn + preSharedKey *wgtypes.Key } // NewWgProxy creates a new Connection Wireguard Proxy -func NewWgProxy(iface string, remoteKey string, allowedIps string, wgAddr string) *WgProxy { +func NewWgProxy(iface string, remoteKey string, allowedIps string, wgAddr string, preSharedKey *wgtypes.Key) *WgProxy { return &WgProxy{ - iface: iface, - remoteKey: remoteKey, - allowedIps: allowedIps, - wgAddr: wgAddr, - close: make(chan struct{}), + iface: iface, + remoteKey: remoteKey, + allowedIps: allowedIps, + wgAddr: wgAddr, + close: make(chan struct{}), + preSharedKey: preSharedKey, } } @@ -48,7 +51,7 @@ func (p *WgProxy) Close() error { // StartLocal configure the interface with a peer using a direct IP:Port endpoint to the remote host func (p *WgProxy) StartLocal(host string) error { - err := iface.UpdatePeer(p.iface, p.remoteKey, p.allowedIps, DefaultWgKeepAlive, host) + err := iface.UpdatePeer(p.iface, p.remoteKey, p.allowedIps, DefaultWgKeepAlive, host, p.preSharedKey) if err != nil { log.Errorf("error while configuring Wireguard peer [%s] %s", p.remoteKey, err.Error()) return err @@ -67,7 +70,7 @@ func (p *WgProxy) Start(remoteConn *ice.Conn) error { p.wgConn = wgConn // add local proxy connection as a Wireguard peer err = iface.UpdatePeer(p.iface, p.remoteKey, p.allowedIps, DefaultWgKeepAlive, - wgConn.LocalAddr().String()) + wgConn.LocalAddr().String(), p.preSharedKey) if err != nil { log.Errorf("error while configuring Wireguard peer [%s] %s", p.remoteKey, err.Error()) return err @@ -92,13 +95,11 @@ func (p *WgProxy) proxyToRemotePeer(remoteConn *ice.Conn) { default: n, err := p.wgConn.Read(buf) if err != nil { - //log.Warnln("failed reading from peer: ", err.Error()) continue } _, err = remoteConn.Write(buf[:n]) if err != nil { - //log.Warnln("failed writing to remote peer: ", err.Error()) continue } } @@ -118,13 +119,11 @@ func (p *WgProxy) proxyToLocalWireguard(remoteConn *ice.Conn) { default: n, err := remoteConn.Read(buf) if err != nil { - //log.Errorf("failed reading from remote connection %s", err) continue } _, err = p.wgConn.Write(buf[:n]) if err != nil { - //log.Errorf("failed writing to local Wireguard instance %s", err) continue } } diff --git a/iface/iface.go b/iface/iface.go index f1da4bdd3..0a6042d08 100644 --- a/iface/iface.go +++ b/iface/iface.go @@ -146,7 +146,7 @@ func GetListenPort(iface string) (*int, error) { // UpdatePeer updates existing Wireguard Peer or creates a new one if doesn't exist // Endpoint is optional -func UpdatePeer(iface string, peerKey string, allowedIps string, keepAlive time.Duration, endpoint string) error { +func UpdatePeer(iface string, peerKey string, allowedIps string, keepAlive time.Duration, endpoint string, preSharedKey *wgtypes.Key) error { log.Debugf("updating interface %s peer %s: endpoint %s ", iface, peerKey, endpoint) @@ -165,6 +165,7 @@ func UpdatePeer(iface string, peerKey string, allowedIps string, keepAlive time. ReplaceAllowedIPs: true, AllowedIPs: []net.IPNet{*ipNet}, PersistentKeepaliveInterval: &keepAlive, + PresharedKey: preSharedKey, } config := wgtypes.Config{ diff --git a/iface/iface_test.go b/iface/iface_test.go index f54ecccc6..a8a89e32c 100644 --- a/iface/iface_test.go +++ b/iface/iface_test.go @@ -111,7 +111,7 @@ func Test_UpdatePeer(t *testing.T) { keepAlive := 15 * time.Second allowedIP := "10.99.99.2/32" endpoint := "127.0.0.1:9900" - err = UpdatePeer(ifaceName, peerPubKey, allowedIP, keepAlive, endpoint) + err = UpdatePeer(ifaceName, peerPubKey, allowedIP, keepAlive, endpoint, nil) if err != nil { t.Fatal(err) } @@ -163,7 +163,7 @@ func Test_UpdatePeerEndpoint(t *testing.T) { keepAlive := 15 * time.Second allowedIP := "10.99.99.2/32" endpoint := "127.0.0.1:9900" - err = UpdatePeer(ifaceName, peerPubKey, allowedIP, keepAlive, endpoint) + err = UpdatePeer(ifaceName, peerPubKey, allowedIP, keepAlive, endpoint, nil) if err != nil { t.Fatal(err) } @@ -204,7 +204,7 @@ func Test_RemovePeer(t *testing.T) { keepAlive := 15 * time.Second allowedIP := "10.99.99.2/32" endpoint := "127.0.0.1:9900" - err = UpdatePeer(ifaceName, peerPubKey, allowedIP, keepAlive, endpoint) + err = UpdatePeer(ifaceName, peerPubKey, allowedIP, keepAlive, endpoint, nil) if err != nil { t.Fatal(err) }