Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix wireguard interface creation on localized windows #2451

Merged
merged 5 commits into from
Jul 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ require (
github.com/gofrs/uuid v3.2.0+incompatible
github.com/golang/protobuf v1.4.2
github.com/huin/goupnp v1.0.0
github.com/jackpal/gateway v1.0.5
github.com/jackpal/gateway v1.0.6
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/julienschmidt/httprouter v1.2.0
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,8 @@ github.com/ipfs/go-ipfs-api v0.0.1/go.mod h1:0FhXgCzrLu7qNmdxZvgYqD9jFzJxzz1NAVt
github.com/ipfs/go-ipfs-files v0.0.1/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4=
github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4=
github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc=
github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc=
github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
github.com/jackpal/gateway v1.0.6 h1:/MJORKvJEwNVldtGVJC2p2cwCnsSoLn3hl3zxmZT7tk=
github.com/jackpal/gateway v1.0.6/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
Expand Down
2 changes: 1 addition & 1 deletion supervisor/daemon/myst.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func (d *Daemon) killMyst() error {
return nil
}

log.Printf("Failed to stop node gracefully, will continue with force kill: %v", err)
log.Warn().Msgf("Failed to stop node gracefully, will continue with force kill: %v", err)
pid, err := mystPid()
if err != nil {
return fmt.Errorf("could not get myst pid: %w", err)
Expand Down
2 changes: 1 addition & 1 deletion supervisor/daemon/responder.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ func (r *responder) err(result ...error) {
func (r *responder) message(msg string) {
log.Debug().Msgf("< %s", msg)
if _, err := fmt.Fprintln(r, msg); err != nil {
log.Printf("Could not send message: %q error: %s\n", msg, err)
log.Err(err).Msgf("Could not send message: %q", msg)
}
}
2 changes: 1 addition & 1 deletion supervisor/daemon/transport/transport_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ func Start(handle handlerFunc, options Options) error {
log.Err(err).Msg("Error closing listener")
}
}()
log.Info().Msg("Waiting for connections...")
for {
log.Info().Msg("Waiting for connections...")
conn, err := l.Accept()
if err != nil {
return fmt.Errorf("accept error: %w", err)
Expand Down
116 changes: 116 additions & 0 deletions supervisor/daemon/wireguard/wginterface/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,15 @@
package wginterface

import (
"bufio"
"fmt"
"net"
"strings"

"github.com/mysteriumnetwork/node/services/wireguard/connection/dns"
"github.com/mysteriumnetwork/node/services/wireguard/wgcfg"
"github.com/mysteriumnetwork/node/utils/netutil"
"github.com/rs/zerolog/log"
"golang.zx2c4.com/wireguard/device"
)

Expand All @@ -31,3 +37,113 @@ type WgInterface struct {
uapi net.Listener
dnsManager dns.Manager
}

// New creates new WgInterface instance.
func New(cfg wgcfg.DeviceConfig, uid string) (*WgInterface, error) {
tunnel, interfaceName, err := createTunnel(cfg.IfaceName)
if err != nil {
return nil, fmt.Errorf("failed to create TUN device %s: %w", cfg.IfaceName, err)
}

logger := newLogger(device.LogLevelDebug, fmt.Sprintf("(%s) ", interfaceName))
logger.Info.Println("Starting wireguard-go version", device.WireGuardGoVersion)

logger.Info.Println("Starting device")
wgDevice := device.NewDevice(tunnel, logger)

log.Info().Msg("Creating UAPI listener")
uapi, err := newUAPIListener(interfaceName)
if err != nil {
return nil, fmt.Errorf("failed to listen on UAPI socket: %w", err)
}

log.Info().Msg("Applying interface configuration")
if err := wgDevice.IpcSetOperation(bufio.NewReader(strings.NewReader(cfg.Encode()))); err != nil {
down(uapi, wgDevice, nil)
return nil, fmt.Errorf("could not set device uapi config: %w", err)
}

log.Info().Msg("Bringing device up")
wgDevice.Up()

log.Info().Msg("Configuring network")
dnsManager := dns.NewManager()
if err := configureNetwork(cfg, dnsManager); err != nil {
down(uapi, wgDevice, dnsManager)
return nil, fmt.Errorf("could not setup network: %w", err)
}

if err := applySocketPermissions(interfaceName, uid); err != nil {
down(uapi, wgDevice, dnsManager)
return nil, fmt.Errorf("could not apply socket permissions: %w", err)
}

wgInterface := &WgInterface{
Name: interfaceName,
Device: wgDevice,
uapi: uapi,
dnsManager: dnsManager,
}
log.Info().Msg("Accepting UAPI requests")
go wgInterface.accept()

return wgInterface, nil
}

// Accept listens for WireGuard configuration changes via user space socket.
func (a *WgInterface) accept() {
for {
conn, err := a.uapi.Accept()
if err != nil {
log.Err(err).Msg("Failed to close UAPI listener")
return
}
go a.Device.IpcHandle(conn)
}
}

func down(uapi net.Listener, d *device.Device, dnsManager dns.Manager) {
if uapi != nil {
if err := uapi.Close(); err != nil {
log.Warn().Err(err).Msg("Could not close uapi socket")
}
}
if d != nil {
d.Close()
}
if dnsManager != nil {
if err := dnsManager.Clean(); err != nil {
log.Err(err).Msg("Could not clean DNS")
}
}
}

// Down closes device and user space api socket.
func (a *WgInterface) Down() {
down(a.uapi, a.Device, a.dnsManager)
}

func configureNetwork(cfg wgcfg.DeviceConfig, dnsManager dns.Manager) error {
if err := netutil.AssignIP(cfg.IfaceName, cfg.Subnet); err != nil {
return fmt.Errorf("failed to assign IP address: %w", err)
}

if cfg.Peer.Endpoint != nil {
if err := netutil.ExcludeRoute(cfg.Peer.Endpoint.IP); err != nil {
return fmt.Errorf("could not exclude route %s: %w", cfg.Peer.Endpoint.IP.String(), err)
}
if err := netutil.AddDefaultRoute(cfg.IfaceName); err != nil {
return fmt.Errorf("could not add default route for %s: %w", cfg.IfaceName, err)
}
}

if err := dnsManager.Set(dns.Config{
ScriptDir: cfg.DNSScriptDir,
IfaceName: cfg.IfaceName,
DNS: cfg.DNS,
}); err != nil {
return fmt.Errorf("could not set DNS: %w", err)
}

return nil
}
123 changes: 20 additions & 103 deletions supervisor/daemon/wireguard/wginterface/interface_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,83 +18,19 @@
package wginterface

import (
"bufio"
"fmt"
"net"
"os"
"path"
"strconv"
"strings"

"github.com/mysteriumnetwork/node/services/wireguard/connection/dns"
"github.com/rs/zerolog/log"

"github.com/mysteriumnetwork/node/services/wireguard/wgcfg"
"github.com/mysteriumnetwork/node/utils/netutil"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/ipc"
"golang.zx2c4.com/wireguard/tun"
)

func socketPath(interfaceName string) string {
return path.Join("/var/run/wireguard", fmt.Sprintf("%s.sock", interfaceName))
}

// New creates new WgInterface instance.
func New(cfg wgcfg.DeviceConfig, uid string) (*WgInterface, error) {
tunnel, interfaceName, err := createTunnel(cfg.IfaceName)
if err != nil {
return nil, fmt.Errorf("failed to create TUN device %s: %w", cfg.IfaceName, err)
}

logger := device.NewLogger(device.LogLevelDebug, fmt.Sprintf("(%s) ", interfaceName))
logger.Info.Println("Starting wireguard-go version", device.WireGuardGoVersion)

wgDevice := device.NewDevice(tunnel, logger)
logger.Info.Println("Device started")

log.Info().Msg("Setting interface configuration")
fileUAPI, err := ipc.UAPIOpen(interfaceName)
if err != nil {
return nil, fmt.Errorf("UAPI listen error: %w", err)
}
uapi, err := ipc.UAPIListen(interfaceName, fileUAPI)
if err != nil {
return nil, fmt.Errorf("failed to listen on UAPI socket: %w", err)
}
if err := wgDevice.IpcSetOperation(bufio.NewReader(strings.NewReader(cfg.Encode()))); err != nil {
return nil, fmt.Errorf("could not set device uapi config: %w", err)
}

log.Info().Msg("Bringing peers up")
wgDevice.Up()

log.Info().Msg("Configuring network")
dnsManager := dns.NewManager()
if err := configureNetwork(cfg, dnsManager); err != nil {
return nil, fmt.Errorf("could not setup network: %w", err)
}

numUid, err := strconv.Atoi(uid)
if err != nil {
return nil, fmt.Errorf("failed to parse uid %s: %w", uid, err)
}
err = os.Chown(socketPath(interfaceName), numUid, -1) // this won't work on windows
if err != nil {
return nil, fmt.Errorf("failed to chown wireguard socket to uid %s: %w", uid, err)
}

wgInterface := &WgInterface{
Name: interfaceName,
Device: wgDevice,
uapi: uapi,
dnsManager: dnsManager,
}
log.Info().Msg("Listening for UAPI requests")
go wgInterface.handleUAPI()

return wgInterface, nil
}

func createTunnel(requestedInterfaceName string) (tunnel tun.Device, interfaceName string, err error) {
tunnel, err = tun.CreateTUN(requestedInterfaceName, device.DefaultMTU)
if err == nil {
Expand All @@ -107,48 +43,29 @@ func createTunnel(requestedInterfaceName string) (tunnel tun.Device, interfaceNa
return tunnel, interfaceName, err
}

// handleUAPI listens for WireGuard configuration changes via user space socket.
func (a *WgInterface) handleUAPI() {
for {
conn, err := a.uapi.Accept()
if err != nil {
log.Err(err).Msg("Failed to close UAPI listener")
return
}
go a.Device.IpcHandle(conn)
func newUAPIListener(interfaceName string) (listener net.Listener, err error) {
log.Info().Msg("Setting interface configuration")
fileUAPI, err := ipc.UAPIOpen(interfaceName)
if err != nil {
return nil, fmt.Errorf("UAPI listen error: %w", err)
}
}

func configureNetwork(cfg wgcfg.DeviceConfig, dnsManager dns.Manager) error {
if err := netutil.AssignIP(cfg.IfaceName, cfg.Subnet); err != nil {
return fmt.Errorf("failed to assign IP address: %w", err)
uapi, err := ipc.UAPIListen(interfaceName, fileUAPI)
if err != nil {
return nil, fmt.Errorf("could not listen for UAPI wg configuration: %w", err)
}
return uapi, nil
}

if cfg.Peer.Endpoint != nil {
if err := netutil.ExcludeRoute(cfg.Peer.Endpoint.IP); err != nil {
return err
}
if err := netutil.AddDefaultRoute(cfg.IfaceName); err != nil {
return err
}
// applySocketPermissions changes ownership of the WireGuard socket to the given user.
func applySocketPermissions(interfaceName string, uid string) error {
numUid, err := strconv.Atoi(uid)
if err != nil {
return fmt.Errorf("failed to parse uid %s: %w", uid, err)
}

if err := dnsManager.Set(dns.Config{
ScriptDir: cfg.DNSScriptDir,
IfaceName: cfg.IfaceName,
DNS: cfg.DNS,
}); err != nil {
return fmt.Errorf("could not set DNS: %w", err)
socketPath := path.Join("/var/run/wireguard", fmt.Sprintf("%s.sock", interfaceName))
err = os.Chown(socketPath, numUid, -1)
if err != nil {
return fmt.Errorf("failed to chown wireguard socket to uid %s: %w", uid, err)
}

return nil
}

// Down closes device and user space api socket.
func (a *WgInterface) Down() {
_ = a.uapi.Close()
a.Device.Close()
if err := a.dnsManager.Clean(); err != nil {
log.Err(err).Msg("Could not clean DNS")
}
}
15 changes: 9 additions & 6 deletions supervisor/daemon/wireguard/wginterface/interface_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,19 @@ package wginterface

import (
"errors"
"net"

"github.com/mysteriumnetwork/node/services/wireguard/wgcfg"
"golang.zx2c4.com/wireguard/tun"
)

// New creates new WgInterface instance.
func New(cfg wgcfg.DeviceConfig, uid string) (*WgInterface, error) {
return nil, errors.New("not implemented")
func createTunnel(requestedInterfaceName string) (tunnel tun.Device, interfaceName string, err error) {
return nil, requestedInterfaceName, errors.New("not implemented")
}

// Down closes device and user space api socket.
func (a *WgInterface) Down() {
func newUAPIListener(interfaceName string) (listener net.Listener, err error) {
return nil, errors.New("not implemented")
}

func applySocketPermissions(interfaceName string, uid string) error {
return errors.New("not implemented")
}
Loading