Skip to content

Commit

Permalink
Merge pull request #2302 from mysteriumnetwork/new-wg-setup
Browse files Browse the repository at this point in the history
Refactor WireGuard device creation
  • Loading branch information
anjmao authored Jun 1, 2020
2 parents 4c390da + ddd9711 commit 9116684
Show file tree
Hide file tree
Showing 24 changed files with 699 additions and 640 deletions.
5 changes: 3 additions & 2 deletions mobile/mysterium/wireguard_connection_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/mysteriumnetwork/node/core/ip"
"github.com/mysteriumnetwork/node/services/wireguard"
wireguard_connection "github.com/mysteriumnetwork/node/services/wireguard/connection"
"github.com/mysteriumnetwork/node/services/wireguard/endpoint/userspace"
"github.com/mysteriumnetwork/node/services/wireguard/key"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
Expand Down Expand Up @@ -238,11 +239,11 @@ func (w *wireguardDeviceImpl) Stats() (*wireguard.Stats, error) {
if w.device == nil {
return nil, errors.New("device is not started")
}
deviceState, err := wireguard.ParseUserspaceDevice(w.device.IpcGetOperation)
deviceState, err := userspace.ParseUserspaceDevice(w.device.IpcGetOperation)
if err != nil {
return nil, errors.Wrap(err, "could not parse userspace wg device state")
}
stats, err := wireguard.ParseDevicePeerStats(deviceState)
stats, err := userspace.ParseDevicePeerStats(deviceState)
if err != nil {
return nil, errors.Wrap(err, "could not get userspace wg peer stats")
}
Expand Down
25 changes: 6 additions & 19 deletions services/wireguard/connection/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ func (c *Connection) Start(ctx context.Context, options connection.ConnectOption
PrivateKey: c.privateKey,
IPAddress: config.Consumer.IPAddress,
ListenPort: config.LocalPort,
Peer: wg.Peer{
Endpoint: &config.Provider.Endpoint,
PublicKey: config.Provider.PublicKey,
AllowedIPs: []string{"0.0.0.0/0", "::/0"},
KeepAlivePeriodSeconds: 18,
},
})
if err != nil {
return errors.Wrap(err, "could not start new connection")
Expand All @@ -135,15 +141,6 @@ func (c *Connection) Start(ctx context.Context, options connection.ConnectOption

log.Info().Msgf("Adding connection peer %s", config.Provider.Endpoint.String())

if err := c.addProviderPeer(conn, config.Provider.Endpoint, config.Provider.PublicKey); err != nil {
return errors.Wrap(err, "failed to add peer to the connection endpoint")
}

log.Info().Msg("Configuring routes")
if err := conn.ConfigureRoutes(config.Provider.Endpoint.IP); err != nil {
return errors.Wrap(err, "failed to configure routes for connection endpoint")
}

log.Info().Msg("Waiting for initial handshake")
if err := c.handshakeWaiter.Wait(conn.PeerStats, c.opts.HandshakeTimeout, c.done); err != nil {
return errors.Wrap(err, "failed while waiting for a peer handshake")
Expand Down Expand Up @@ -176,16 +173,6 @@ func (c *Connection) startConn(conf wg.ConsumerModeConfig) (wg.ConnectionEndpoin
return conn, nil
}

func (c *Connection) addProviderPeer(conn wg.ConnectionEndpoint, endpoint net.UDPAddr, publicKey string) error {
peerInfo := wg.Peer{
Endpoint: &endpoint,
PublicKey: publicKey,
AllowedIPs: []string{"0.0.0.0/0", "::/0"},
KeepAlivePeriodSeconds: 18,
}
return conn.AddPeer(conn.InterfaceName(), peerInfo)
}

// Wait blocks until wireguard connection not stopped.
func (c *Connection) Wait() error {
<-c.done
Expand Down
181 changes: 181 additions & 0 deletions services/wireguard/device_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
* Copyright (C) 2020 The "MysteriumNetwork/node" Authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package wireguard

import (
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"net"
"strings"
"time"

"github.com/rs/zerolog/log"
)

// Stats represents wireguard peer statistics information.
type Stats struct {
BytesSent uint64
BytesReceived uint64
LastHandshake time.Time
}

// DeviceConfig describes wireguard device configuration.
type DeviceConfig struct {
IfaceName string `json:"iface_name"`
Subnet net.IPNet `json:"subnet"`
PrivateKey string `json:"private_key"`
ListenPort int `json:"listen_port"`

Peer Peer `json:"peer"`
}

// MarshalJSON implements json.Marshaler interface to provide human readable configuration.
func (dc DeviceConfig) MarshalJSON() ([]byte, error) {
type peer struct {
PublicKey string `json:"public_key"`
Endpoint string `json:"endpoint"`
AllowedIPs []string `json:"allowed_i_ps"`
KeepAlivePeriodSeconds int `json:"keep_alive_period_seconds"`
}

type deviceConfig struct {
IfaceName string `json:"iface_name"`
Subnet string `json:"subnet"`
PrivateKey string `json:"private_key"`
ListenPort int `json:"listen_port"`
Peer peer `json:"peer"`
}

var peerEndpoint string
if dc.Peer.Endpoint != nil {
peerEndpoint = dc.Peer.Endpoint.String()
}

return json.Marshal(&deviceConfig{
IfaceName: dc.IfaceName,
Subnet: dc.Subnet.String(),
PrivateKey: dc.PrivateKey,
ListenPort: dc.ListenPort,
Peer: peer{
PublicKey: dc.Peer.PublicKey,
Endpoint: peerEndpoint,
AllowedIPs: dc.Peer.AllowedIPs,
KeepAlivePeriodSeconds: dc.Peer.KeepAlivePeriodSeconds,
},
})
}

// UnmarshalJSON implements json.Unmarshaler interface to receive human readable configuration.
func (dc *DeviceConfig) UnmarshalJSON(data []byte) error {
type peer struct {
PublicKey string `json:"public_key"`
Endpoint string `json:"endpoint"`
AllowedIPs []string `json:"allowed_i_ps"`
KeepAlivePeriodSeconds int `json:"keep_alive_period_seconds"`
}

type deviceConfig struct {
IfaceName string `json:"iface_name"`
Subnet string `json:"subnet"`
PrivateKey string `json:"private_key"`
ListenPort int `json:"listen_port"`
Peer peer `json:"peer"`
}

cfg := deviceConfig{}

if err := json.Unmarshal(data, &cfg); err != nil {
return fmt.Errorf("could not unmarshal device config: %w", err)
}

ip, ipnet, err := net.ParseCIDR(cfg.Subnet)
if err != nil {
return fmt.Errorf("could not parse subnet: %w", err)
}

var peerEndpoint *net.UDPAddr
if cfg.Peer.Endpoint != "" {
peerEndpoint, err = net.ResolveUDPAddr("udp", cfg.Peer.Endpoint)
if err != nil {
return fmt.Errorf("could not resolve peer endpoint: %w", err)
}
}

dc.IfaceName = cfg.IfaceName
dc.Subnet = *ipnet
dc.Subnet.IP = ip
dc.PrivateKey = cfg.PrivateKey
dc.ListenPort = cfg.ListenPort
dc.Peer = Peer{
PublicKey: cfg.Peer.PublicKey,
Endpoint: peerEndpoint,
AllowedIPs: cfg.Peer.AllowedIPs,
KeepAlivePeriodSeconds: cfg.Peer.KeepAlivePeriodSeconds,
}

return nil
}

// Encode encodes device config into string representation which is used for
// userspace and kernel space wireguard configuration.
func (dc *DeviceConfig) Encode() string {
var res strings.Builder
keyBytes, err := base64.StdEncoding.DecodeString(dc.PrivateKey)
if err != nil {
log.Err(err).Msg("Could not decode device private key. Will use empty config.")
return ""
}
hexKey := hex.EncodeToString(keyBytes)

res.WriteString(fmt.Sprintf("private_key=%s\n", hexKey))
res.WriteString(fmt.Sprintf("listen_port=%d\n", dc.ListenPort))
res.WriteString(dc.Peer.Encode())
return res.String()
}

// Peer represents wireguard peer.
type Peer struct {
PublicKey string `json:"public_key"`
Endpoint *net.UDPAddr `json:"endpoint"`
AllowedIPs []string `json:"allowed_i_ps"`
KeepAlivePeriodSeconds int `json:"keep_alive_period_seconds"`
}

// Encode encodes device peer config into string representation which is used for
// userspace and kernel space wireguard configuration.
func (p *Peer) Encode() string {
var res strings.Builder

keyBytes, err := base64.StdEncoding.DecodeString(p.PublicKey)
if err != nil {
log.Err(err).Msg("Could not decode device public key. Will use empty config.")
return ""
}
hexKey := hex.EncodeToString(keyBytes)
res.WriteString(fmt.Sprintf("public_key=%s\n", hexKey))
res.WriteString(fmt.Sprintf("persistent_keepalive_interval=%d\n", p.KeepAlivePeriodSeconds))
if p.Endpoint != nil {
res.WriteString(fmt.Sprintf("endpoint=%s\n", p.Endpoint.String()))
}
for _, ip := range p.AllowedIPs {
res.WriteString(fmt.Sprintf("allowed_ip=%s\n", ip))
}
return res.String()
}
Loading

0 comments on commit 9116684

Please sign in to comment.