feature: add Wireguard preshared-key support (#160)

This commit is contained in:
Mikhail Bragin 2021-11-21 17:47:19 +01:00 committed by GitHub
parent edd4125742
commit 6b7d4cf644
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 51 additions and 35 deletions

View File

@ -30,10 +30,9 @@ var (
return err return err
} }
config, err := internal.GetConfig(managementURL, configPath) config, err := internal.GetConfig(managementURL, configPath, preSharedKey)
if err != nil { if err != nil {
log.Errorf("failed getting config %s %v", configPath, err) log.Errorf("failed getting config %s %v", configPath, err)
//os.Exit(ExitSetupFailed)
return err return err
} }
@ -41,7 +40,6 @@ var (
myPrivateKey, err := wgtypes.ParseKey(config.PrivateKey) myPrivateKey, err := wgtypes.ParseKey(config.PrivateKey)
if err != nil { if err != nil {
log.Errorf("failed parsing Wireguard key %s: [%s]", config.PrivateKey, err.Error()) log.Errorf("failed parsing Wireguard key %s: [%s]", config.PrivateKey, err.Error())
//os.Exit(ExitSetupFailed)
return err return err
} }
@ -56,7 +54,6 @@ var (
mgmClient, err := mgm.NewClient(ctx, config.ManagementURL.Host, myPrivateKey, mgmTlsEnabled) mgmClient, err := mgm.NewClient(ctx, config.ManagementURL.Host, myPrivateKey, mgmTlsEnabled)
if err != nil { if err != nil {
log.Errorf("failed connecting to Management Service %s %v", config.ManagementURL.String(), err) log.Errorf("failed connecting to Management Service %s %v", config.ManagementURL.String(), err)
//os.Exit(ExitSetupFailed)
return err return err
} }
log.Debugf("connected to anagement Service %s", config.ManagementURL.String()) log.Debugf("connected to anagement Service %s", config.ManagementURL.String())
@ -64,21 +61,18 @@ var (
serverKey, err := mgmClient.GetServerPublicKey() serverKey, err := mgmClient.GetServerPublicKey()
if err != nil { if err != nil {
log.Errorf("failed while getting Management Service public key: %v", err) log.Errorf("failed while getting Management Service public key: %v", err)
//os.Exit(ExitSetupFailed)
return err return err
} }
_, err = loginPeer(*serverKey, mgmClient, setupKey) _, err = loginPeer(*serverKey, mgmClient, setupKey)
if err != nil { if err != nil {
log.Errorf("failed logging-in peer on Management Service : %v", err) log.Errorf("failed logging-in peer on Management Service : %v", err)
//os.Exit(ExitSetupFailed)
return err return err
} }
err = mgmClient.Close() err = mgmClient.Close()
if err != nil { if err != nil {
log.Errorf("failed closing Management Service client: %v", err) log.Errorf("failed closing Management Service client: %v", err)
//os.Exit(ExitSetupFailed)
return err return err
} }

View File

@ -21,6 +21,7 @@ var (
logFile string logFile string
managementURL string managementURL string
setupKey string setupKey string
preSharedKey string
rootCmd = &cobra.Command{ rootCmd = &cobra.Command{
Use: "wiretrustee", Use: "wiretrustee",
Short: "", Short: "",
@ -53,6 +54,7 @@ func init() {
rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "sets Wiretrustee log level") 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(&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(&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(serviceCmd)
rootCmd.AddCommand(upCmd) rootCmd.AddCommand(upCmd)
rootCmd.AddCommand(loginCmd) rootCmd.AddCommand(loginCmd)

View File

@ -63,12 +63,22 @@ func createEngineConfig(key wgtypes.Key, config *internal.Config, peerConfig *mg
iFaceBlackList[config.IFaceBlackList[i]] = struct{}{} iFaceBlackList[config.IFaceBlackList[i]] = struct{}{}
} }
return &internal.EngineConfig{ engineConf := &internal.EngineConfig{
WgIface: config.WgIface, WgIface: config.WgIface,
WgAddr: peerConfig.Address, WgAddr: peerConfig.Address,
IFaceBlackList: iFaceBlackList, IFaceBlackList: iFaceBlackList,
WgPrivateKey: key, 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 // connectToSignal creates Signal Service client and established a connection

View File

@ -28,13 +28,14 @@ func init() {
type Config struct { type Config struct {
// Wireguard private key of local peer // Wireguard private key of local peer
PrivateKey string PrivateKey string
PreSharedKey string
ManagementURL *url.URL ManagementURL *url.URL
WgIface string WgIface string
IFaceBlackList []string IFaceBlackList []string
} }
//createNewConfig creates a new config generating a new Wireguard key and saving to file //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() wgKey := generateKey()
config := &Config{PrivateKey: wgKey, WgIface: iface.WgInterfaceDefault, IFaceBlackList: []string{}} config := &Config{PrivateKey: wgKey, WgIface: iface.WgInterfaceDefault, IFaceBlackList: []string{}}
if managementURL != "" { if managementURL != "" {
@ -47,6 +48,10 @@ func createNewConfig(managementURL string, configPath string) (*Config, error) {
config.ManagementURL = managementURLDefault config.ManagementURL = managementURLDefault
} }
if preSharedKey != "" {
config.PreSharedKey = preSharedKey
}
config.IFaceBlackList = []string{iface.WgInterfaceDefault, "tun0"} config.IFaceBlackList = []string{iface.WgInterfaceDefault, "tun0"}
err := util.WriteJson(configPath, config) 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 // 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) { if _, err := os.Stat(configPath); os.IsNotExist(err) {
log.Infof("generating new config %s", configPath) log.Infof("generating new config %s", configPath)
return createNewConfig(managementURL, configPath) return createNewConfig(managementURL, configPath, preSharedKey)
} else { } else {
return ReadConfig(managementURL, configPath) return ReadConfig(managementURL, configPath)
} }

View File

@ -60,6 +60,8 @@ type ConnConfig struct {
// Remote Wireguard public key // Remote Wireguard public key
RemoteWgKey wgtypes.Key RemoteWgKey wgtypes.Key
PreSharedKey *wgtypes.Key
StunTurnURLS []*ice.URL StunTurnURLS []*ice.URL
iFaceBlackList map[string]struct{} iFaceBlackList map[string]struct{}
@ -115,7 +117,7 @@ func NewConnection(config ConnConfig,
closeCond: NewCond(), closeCond: NewCond(),
connected: NewCond(), connected: NewCond(),
agent: nil, 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, Status: StatusDisconnected,
} }
} }

View File

@ -30,6 +30,8 @@ type EngineConfig struct {
WgPrivateKey wgtypes.Key WgPrivateKey wgtypes.Key
// IFaceBlackList is a list of network interfaces to ignore when discovering connection candidates (ICE related) // IFaceBlackList is a list of network interfaces to ignore when discovering connection candidates (ICE related)
IFaceBlackList map[string]struct{} 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. // 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, RemoteWgKey: remoteKey,
StunTurnURLS: append(e.STUNs, e.TURNs...), StunTurnURLS: append(e.STUNs, e.TURNs...),
iFaceBlackList: e.config.IFaceBlackList, iFaceBlackList: e.config.IFaceBlackList,
PreSharedKey: e.config.PreSharedKey,
} }
signalOffer := func(uFrag string, pwd string) error { signalOffer := func(uFrag string, pwd string) error {

View File

@ -4,27 +4,30 @@ import (
ice "github.com/pion/ice/v2" ice "github.com/pion/ice/v2"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/wiretrustee/wiretrustee/iface" "github.com/wiretrustee/wiretrustee/iface"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"net" "net"
) )
// WgProxy an instance of an instance of the Connection Wireguard Proxy // WgProxy an instance of an instance of the Connection Wireguard Proxy
type WgProxy struct { type WgProxy struct {
iface string iface string
remoteKey string remoteKey string
allowedIps string allowedIps string
wgAddr string wgAddr string
close chan struct{} close chan struct{}
wgConn net.Conn wgConn net.Conn
preSharedKey *wgtypes.Key
} }
// NewWgProxy creates a new Connection Wireguard Proxy // 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{ return &WgProxy{
iface: iface, iface: iface,
remoteKey: remoteKey, remoteKey: remoteKey,
allowedIps: allowedIps, allowedIps: allowedIps,
wgAddr: wgAddr, wgAddr: wgAddr,
close: make(chan struct{}), 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 // StartLocal configure the interface with a peer using a direct IP:Port endpoint to the remote host
func (p *WgProxy) StartLocal(host string) error { 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 { if err != nil {
log.Errorf("error while configuring Wireguard peer [%s] %s", p.remoteKey, err.Error()) log.Errorf("error while configuring Wireguard peer [%s] %s", p.remoteKey, err.Error())
return err return err
@ -67,7 +70,7 @@ func (p *WgProxy) Start(remoteConn *ice.Conn) error {
p.wgConn = wgConn p.wgConn = wgConn
// add local proxy connection as a Wireguard peer // add local proxy connection as a Wireguard peer
err = iface.UpdatePeer(p.iface, p.remoteKey, p.allowedIps, DefaultWgKeepAlive, err = iface.UpdatePeer(p.iface, p.remoteKey, p.allowedIps, DefaultWgKeepAlive,
wgConn.LocalAddr().String()) wgConn.LocalAddr().String(), p.preSharedKey)
if err != nil { if err != nil {
log.Errorf("error while configuring Wireguard peer [%s] %s", p.remoteKey, err.Error()) log.Errorf("error while configuring Wireguard peer [%s] %s", p.remoteKey, err.Error())
return err return err
@ -92,13 +95,11 @@ func (p *WgProxy) proxyToRemotePeer(remoteConn *ice.Conn) {
default: default:
n, err := p.wgConn.Read(buf) n, err := p.wgConn.Read(buf)
if err != nil { if err != nil {
//log.Warnln("failed reading from peer: ", err.Error())
continue continue
} }
_, err = remoteConn.Write(buf[:n]) _, err = remoteConn.Write(buf[:n])
if err != nil { if err != nil {
//log.Warnln("failed writing to remote peer: ", err.Error())
continue continue
} }
} }
@ -118,13 +119,11 @@ func (p *WgProxy) proxyToLocalWireguard(remoteConn *ice.Conn) {
default: default:
n, err := remoteConn.Read(buf) n, err := remoteConn.Read(buf)
if err != nil { if err != nil {
//log.Errorf("failed reading from remote connection %s", err)
continue continue
} }
_, err = p.wgConn.Write(buf[:n]) _, err = p.wgConn.Write(buf[:n])
if err != nil { if err != nil {
//log.Errorf("failed writing to local Wireguard instance %s", err)
continue continue
} }
} }

View File

@ -146,7 +146,7 @@ func GetListenPort(iface string) (*int, error) {
// UpdatePeer updates existing Wireguard Peer or creates a new one if doesn't exist // UpdatePeer updates existing Wireguard Peer or creates a new one if doesn't exist
// Endpoint is optional // 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) 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, ReplaceAllowedIPs: true,
AllowedIPs: []net.IPNet{*ipNet}, AllowedIPs: []net.IPNet{*ipNet},
PersistentKeepaliveInterval: &keepAlive, PersistentKeepaliveInterval: &keepAlive,
PresharedKey: preSharedKey,
} }
config := wgtypes.Config{ config := wgtypes.Config{

View File

@ -111,7 +111,7 @@ func Test_UpdatePeer(t *testing.T) {
keepAlive := 15 * time.Second keepAlive := 15 * time.Second
allowedIP := "10.99.99.2/32" allowedIP := "10.99.99.2/32"
endpoint := "127.0.0.1:9900" endpoint := "127.0.0.1:9900"
err = UpdatePeer(ifaceName, peerPubKey, allowedIP, keepAlive, endpoint) err = UpdatePeer(ifaceName, peerPubKey, allowedIP, keepAlive, endpoint, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -163,7 +163,7 @@ func Test_UpdatePeerEndpoint(t *testing.T) {
keepAlive := 15 * time.Second keepAlive := 15 * time.Second
allowedIP := "10.99.99.2/32" allowedIP := "10.99.99.2/32"
endpoint := "127.0.0.1:9900" endpoint := "127.0.0.1:9900"
err = UpdatePeer(ifaceName, peerPubKey, allowedIP, keepAlive, endpoint) err = UpdatePeer(ifaceName, peerPubKey, allowedIP, keepAlive, endpoint, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -204,7 +204,7 @@ func Test_RemovePeer(t *testing.T) {
keepAlive := 15 * time.Second keepAlive := 15 * time.Second
allowedIP := "10.99.99.2/32" allowedIP := "10.99.99.2/32"
endpoint := "127.0.0.1:9900" endpoint := "127.0.0.1:9900"
err = UpdatePeer(ifaceName, peerPubKey, allowedIP, keepAlive, endpoint) err = UpdatePeer(ifaceName, peerPubKey, allowedIP, keepAlive, endpoint, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }