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

Make wireguard connect work without sudo #2193

Merged
merged 3 commits into from
May 13, 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
9 changes: 7 additions & 2 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,15 @@ package:linux-raspberry-image:
tags: [go,high_performance]
script: go run mage.go -v PackageLinuxRaspberryImage

package:osx-amd64:
package:macos-amd64:
stage: build
tags: [go]
script: go run mage.go -v PackageOsxAmd64
script: go run mage.go -v PackageMacOSAmd64

package:supervisor-macos-amd64:
stage: build
tags: [go]
script: go run mage.go -v PackageSupervisorMacOSAmd64

package:windows-amd64:
stage: build
Expand Down
1 change: 0 additions & 1 deletion bin/build
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,3 @@ fi
mkdir -p $GOBIN/config
copy_config $GOOS $GOBIN

exit 0
2 changes: 1 addition & 1 deletion bin/builder_package
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ while test $# -gt 0; do
done

printf "\e[0;32m%s\e[0m\n" "Docker image building process complete!"
exit 0

2 changes: 1 addition & 1 deletion bin/package_standalone
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ fi
rm -rf ${DIR_TEMP}

print_success "Standalone package '$PACKAGE_FILE' complete!"
exit 0

54 changes: 54 additions & 0 deletions bin/package_supervisor
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/bin/bash

###########################################################################
# Packaging script which creates standalone supervisor package.
#
# Usage:
#
# Package (specific OS and arch: linux, darwin, windows):
#> GOOS=darwin GOARCH=amd64 bin/package_standalone
#

set -e

source bin/helpers/output.sh
source bin/helpers/functions.sh

if [[ ! "$GOOS" =~ ^(linux|darwin|windows)$ ]]; then
print_error "Missing OS! Should be: linux, darwin or windows"
exit 1
fi

if [[ ! "$GOARCH" =~ ^(amd64|arm)$ ]]; then
print_error "Missing ARCH! Should be: amd64 or arm"
exit 1
fi

BINARY=${BINARY:-"build/supervisor/supervisor"}
DIR_BUILD="build/package"

mkdir -p $DIR_BUILD
go build -o $BINARY ./cmd/supervisor

# Put all files to package directory (to avoid preserving directory structure)
printf "Building supervisor package for OS '$GOOS/$GOARCH' ..\n"
DIR_TEMP=`mktemp -d ${DIR_BUILD}/${tempname}.XXXXXX`

if [ "$OS" == "windows" ]; then
cp -vp ${BINARY} ${DIR_TEMP}/myst_supervisor.exe
else
cp -vp ${BINARY} ${DIR_TEMP}/myst_supervisor
fi

# Tarball package directory
if [ "$OS" == "windows" ]; then
PACKAGE_FILE="${DIR_BUILD}/`basename -s .exe ${BINARY}`.zip"
(cd ${DIR_TEMP} && zip -r - .) > ${PACKAGE_FILE}
else
PACKAGE_FILE="${DIR_BUILD}/`basename ${BINARY}`.tar.gz"
tar -zcv -f ${PACKAGE_FILE} -C ${DIR_TEMP} .
fi
rm -rf ${DIR_TEMP}

print_success "Supervisor package '$PACKAGE_FILE' complete!"

22 changes: 20 additions & 2 deletions ci/packages/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,24 @@ func PackageLinuxDebianArm64() error {
return env.IfRelease(storage.UploadArtifacts)
}

// PackageOsxAmd64 builds and stores OSX amd64 package
func PackageOsxAmd64() error {
// PackageMacOSAmd64 builds and stores macOS amd64 package
func PackageMacOSAmd64() error {
logconfig.Bootstrap()
if err := packageStandalone("build/myst/myst_darwin_amd64", "darwin", "amd64"); err != nil {
return err
}
return env.IfRelease(storage.UploadArtifacts)
}

// PackageSupervisorMacOSAmd64 builds and stores macOS amd64 supervisor package
func PackageSupervisorMacOSAmd64() error {
logconfig.Bootstrap()
if err := packageSupervisor("darwin", "amd64"); err != nil {
return err
}
return env.IfRelease(storage.UploadArtifacts)
}

// PackageWindowsAmd64 builds and stores Windows amd64 package
func PackageWindowsAmd64() error {
logconfig.Bootstrap()
Expand Down Expand Up @@ -278,6 +287,15 @@ func packageStandalone(binaryPath, os, arch string) error {
return sh.RunWith(envs, "bin/package_standalone", os, arch)
}

func packageSupervisor(os, arch string) error {
log.Info().Msgf("Packaging supervisor %s %s", os, arch)
envs := map[string]string{
"GOOS": os,
"GOARCH": arch,
}
return sh.RunWith(envs, "bin/package_supervisor", os, arch)
}

func packageDebian(binaryPath, arch string) error {
if err := env.EnsureEnvVars(env.BuildVersion); err != nil {
return err
Expand Down
27 changes: 27 additions & 0 deletions cmd/supervisor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# node-supervisor

Supervisor is a system background service that allows seamless installation/running of [Mysterium node](https://github.com/mysteriumnetwork/node) under elevated permissions.
Clients (e.g. desktop applications) can ask the supervisor to RUN or KILL the node instance via OS dependent mechanism.

Currently, only macOS is supported and it is using unix domain sockets for communication.

For usage see:

```
myst_supervisor -help
```

## Elevated command support table

| Command | OS | Args | Output | Implemented | Notes |
| --------------------------------- | ------------ | ---- | ------ | ----------- | ----- |
| isWgSupported (kernel) | linux | | ok | - | |
| NAT ipForward | linux, macOS | | ok | - | | `/sbin/sysctl -w net.ipv4.ip_forward=1` |
| NAT/firewall rules | ALL | vpnNetwork <br> dnsIP <br> dnsPort <br> protectedNetworks <br> providerExternalIP <br> enableDNSRedirect | ok | - | |
| NAT/firewall allowIP | linux | IP | ok | - | |
| NAT/firewall allowURL | linux | URL | ok | - | |
| Create tun (wg userspace) | ALL | iface name | `windows.GUID / FD int` | - | FD to be used in `wg/tun.CreateTUNFromFile(*os.File, int) (Device, error)` see `tun_linux.go/tun_darwin.go` <br> windows: `CreateTUNWithRequestedGUID` |
| Destroy device (wg userspace) | ALL | iface name | ok |
| assignIP | ALL | iface name, subnet | ok |
| excludeRoute | ALL | IP | ok |
| defaultRoute | ALL | iface name | ok |
96 changes: 96 additions & 0 deletions cmd/supervisor/supervisor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* 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 main

import (
"flag"
"fmt"
"log"
"os"
"path/filepath"

"github.com/mysteriumnetwork/node/supervisor/config"
"github.com/mysteriumnetwork/node/supervisor/daemon"
"github.com/mysteriumnetwork/node/supervisor/install"
)

var (
flagInstall = flag.Bool("install", false, "Install or repair myst supervisor")
flagMystHome = flag.String("mystHome", "", "Home directory for running myst (required for -install)")
flagMystPath = flag.String("mystPath", "", "Path to myst executable (required for -install)")
flagOpenVPNPath = flag.String("openvpnPath", "", "Path to openvpn executable (required for -install)")
)

func ensureInstallFlags() {
if *flagMystHome == "" || *flagMystPath == "" || *flagOpenVPNPath == "" {
fmt.Println("Error: required flags were not set")
flag.Usage()
os.Exit(1)
}
}

func main() {
flag.Parse()

if *flagInstall {
ensureInstallFlags()
log.Println("Installing supervisor")
path, err := thisPath()
if err != nil {
log.Fatalln("Failed to determine supervisor's path:", err)
}
err = install.Install(install.Options{
SupervisorPath: path,
})
if err != nil {
log.Fatalln("Failed to install supervisor:", err)
}
log.Println("Creating supervisor configuration")
cfg := config.Config{
MystHome: *flagMystHome,
MystPath: *flagMystPath,
OpenVPNPath: *flagOpenVPNPath,
}
err = cfg.Write()
if err != nil {
log.Fatalln("Failed to create supervisor configuration:", err)
}
} else {
log.Println("Running myst supervisor daemon")
cfg, err := config.Read()
if err != nil {
log.Println("Failed to read supervisor configuration:", err)
}
supervisor := daemon.New(cfg)
if err := supervisor.Start(); err != nil {
log.Fatalln("Error running supervisor:", err)
}
}
}

func thisPath() (string, error) {
thisExec, err := os.Executable()
if err != nil {
return "", err
}
thisPath, err := filepath.Abs(thisExec)
if err != nil {
return "", err
}
return thisPath, nil
}
10 changes: 9 additions & 1 deletion config/flags_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ var (
Usage: "the port to run ui on",
Value: 4449,
}
// FlagUserMode allows to run node under current user without sudo.
FlagUserMode = cli.BoolFlag{
Name: "usermode",
Usage: "Run as a regular user. Delegate elevated commands to the supervisor.",
Value: false,
}
// FlagVendorID identifies 3rd party vendor (distributor) of Mysterium node.
FlagVendorID = cli.StringFlag{
Name: "vendor.id",
Expand Down Expand Up @@ -216,9 +222,10 @@ func RegisterFlagsNode(flags *[]cli.Flag) error {
&FlagQualityAddress,
&FlagTequilapiAddress,
&FlagTequilapiPort,
&FlagUIEnable,
&FlagPProfEnable,
&FlagUIEnable,
&FlagUIPort,
&FlagUserMode,
&FlagVendorID,
&FlagP2PListenPorts,
)
Expand Down Expand Up @@ -258,6 +265,7 @@ func ParseFlagsNode(ctx *cli.Context) {
Current.ParseBoolFlag(ctx, FlagPProfEnable)
Current.ParseBoolFlag(ctx, FlagUIEnable)
Current.ParseIntFlag(ctx, FlagUIPort)
Current.ParseBoolFlag(ctx, FlagUserMode)
Current.ParseStringFlag(ctx, FlagVendorID)
Current.ParseStringFlag(ctx, FlagP2PListenPorts)

Expand Down
8 changes: 0 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -469,8 +469,6 @@ github.com/mysteriumnetwork/go-ci v0.0.0-20200121125840-b99aac3d815c h1:8LI4spVF
github.com/mysteriumnetwork/go-ci v0.0.0-20200121125840-b99aac3d815c/go.mod h1:GlJmsQDFyRmV9psEs/Mt/humLALu8xmZ7blXQ6Rc9Rs=
github.com/mysteriumnetwork/go-ci v0.0.0-20200415074834-39fc864b0ed4 h1:t18FszkN3GHd3lE95/5I6YlrvhiQCdWP58JOeVfhi1E=
github.com/mysteriumnetwork/go-ci v0.0.0-20200415074834-39fc864b0ed4/go.mod h1:GlJmsQDFyRmV9psEs/Mt/humLALu8xmZ7blXQ6Rc9Rs=
github.com/mysteriumnetwork/go-dvpn-web v0.0.39 h1:XTPr3tNAZKcdYOG8ElXOdTYvN2URQ+uyKtre3SzMjGo=
github.com/mysteriumnetwork/go-dvpn-web v0.0.39/go.mod h1:2wlR34GPZfnJxSc+0KZMoRCEDW0RVPVFv7bRC1QOZnU=
github.com/mysteriumnetwork/go-dvpn-web v0.0.40 h1:iuK/J+1BFbR189KWgsSfmEQakCl6rwE1TOKWqDMf6+0=
github.com/mysteriumnetwork/go-dvpn-web v0.0.40/go.mod h1:2wlR34GPZfnJxSc+0KZMoRCEDW0RVPVFv7bRC1QOZnU=
github.com/mysteriumnetwork/go-openvpn v0.0.23 h1:6BKoTwU9CpJL/Na9M9a0uaelAaVIo/XZPDpElfzFjxM=
Expand Down Expand Up @@ -708,8 +706,6 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
Expand Down Expand Up @@ -763,8 +759,6 @@ golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200505041828-1ed23360d12c h1:zJ0mtu4jCalhKg6Oaukv6iIkb+cOvDrajDH9DH46Q4M=
golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f h1:QBjCr1Fz5kw158VqdE9JfI9cJnl/ymnJWAdMuinqL7Y=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
Expand Down Expand Up @@ -818,8 +812,6 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 h1:5B6i6EAiSYyejWfvc5Rc9BbI3rzIsrrXfAQBWnYfn+w=
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f h1:mOhmO9WsBaJCNmaZHPtHs9wOcdqdKCjF6OPJlmDM3KI=
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
3 changes: 2 additions & 1 deletion services/wireguard/connection/handshake.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package connection

import (
"errors"
"fmt"
"net"
"time"

Expand Down Expand Up @@ -51,7 +52,7 @@ func (h *handshakeWaiter) Wait(statsFetch func() (*wireguard.Stats, error), time
case <-time.After(100 * time.Millisecond):
stats, err := statsFetch()
if err != nil {
return err
return fmt.Errorf("failed to fetch stats: %w", err)
}
if !stats.LastHandshake.IsZero() {
return nil
Expand Down
5 changes: 3 additions & 2 deletions services/wireguard/endpoint/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ type connectionEndpoint struct {
ipAddr net.IPNet
endpoint net.UDPAddr
resourceAllocator *resources.Allocator
wgClient wgClient
wgClient WgClient
}

// StartConsumerMode starts and configure wireguard network interface running in consumer mode.
Expand All @@ -61,6 +61,7 @@ func (ce *connectionEndpoint) StartConsumerMode(config wg.ConsumerModeConfig) er
if err != nil {
return errors.Wrap(err, "could not allocate interface")
}
log.Debug().Msgf("Allocated interface: %s", iface)

ce.iface = iface
ce.ipAddr = config.IPAddress
Expand Down Expand Up @@ -134,7 +135,7 @@ func (ce *connectionEndpoint) RemovePeer(publicKey string) error {

// PeerStats returns stats information about connected peer.
func (ce *connectionEndpoint) PeerStats() (*wg.Stats, error) {
return ce.wgClient.PeerStats()
return ce.wgClient.PeerStats(ce.iface)
}

// Config provides wireguard service configuration for the current connection endpoint.
Expand Down
2 changes: 1 addition & 1 deletion services/wireguard/endpoint/kernelspace/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (c *client) RemovePeer(iface string, publicKey string) error {
}}})
}

func (c *client) PeerStats() (*wg.Stats, error) {
func (c *client) PeerStats(string) (*wg.Stats, error) {
d, err := c.wgClient.Device(c.iface)
if err != nil {
return nil, err
Expand Down
Loading