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

Move run command from vpn to osutil, add RunWithResult #685

Closed
wants to merge 4 commits into from
Closed
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
25 changes: 1 addition & 24 deletions internal/vpn/errors.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,7 @@
package vpn

import (
"errors"
)
import "errors"

var (
errCouldFindDefaultNetworkGateway = errors.New("could not find default network gateway")
)

// ErrorWithStderr is an error raised by the external process.
// `Err` is an actual error coming from `exec`, while `Stderr` contains
// stderr output of the process.
type ErrorWithStderr struct {
Err error
Stderr []byte
}

// NewErrorWithStderr constructs new `ErrorWithStderr`.
func NewErrorWithStderr(err error, stderr []byte) *ErrorWithStderr {
return &ErrorWithStderr{
Err: err,
Stderr: stderr,
}
}

// Error implements `error`.
func (e *ErrorWithStderr) Error() string {
return e.Err.Error() + ": " + string(e.Stderr)
}
25 changes: 0 additions & 25 deletions internal/vpn/os.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
package vpn

import (
"bytes"
"fmt"
"io"
"net"
"os"
"os/exec"
"strings"
)

// LocalNetworkInterfaceIPs gets IPs of all local interfaces.
Expand Down Expand Up @@ -83,23 +78,3 @@ func parseCIDR(ipCIDR string) (ipStr, netmask string, err error) {

return ip.String(), fmt.Sprintf("%d.%d.%d.%d", net.Mask[0], net.Mask[1], net.Mask[2], net.Mask[3]), nil
}

//nolint:unparam
func run(bin string, args ...string) error {
fullCmd := bin + " " + strings.Join(args, " ")

cmd := exec.Command(bin, args...) //nolint:gosec

stderrBuf := bytes.NewBuffer(nil)

cmd.Stderr = io.MultiWriter(os.Stderr, stderrBuf)
cmd.Stdout = os.Stdout
cmd.Stdin = os.Stdin

if err := cmd.Run(); err != nil {
return NewErrorWithStderr(fmt.Errorf("error running command \"%s\": %w", fullCmd, err),
stderrBuf.Bytes())
}

return nil
}
23 changes: 8 additions & 15 deletions internal/vpn/os_client_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ package vpn

import (
"bytes"
"fmt"
"net"
"os/exec"
"syscall"

"github.com/skycoin/skywire/pkg/util/osutil"
)

const (
Expand All @@ -16,9 +15,9 @@ const (

// DefaultNetworkGateway fetches system's default network gateway.
func DefaultNetworkGateway() (net.IP, error) {
outputBytes, err := exec.Command("sh", "-c", defaultNetworkGatewayCMD).Output()
outputBytes, err := osutil.RunWithResult("sh", "-c", defaultNetworkGatewayCMD)
if err != nil {
return nil, fmt.Errorf("error running command %s: %w", defaultNetworkGatewayCMD, err)
return nil, err
}

outputBytes = bytes.TrimRight(outputBytes, "\n")
Expand All @@ -38,16 +37,10 @@ func DefaultNetworkGateway() (net.IP, error) {
return nil, errCouldFindDefaultNetworkGateway
}

func setupClientSysPrivileges() (suid int, err error) {
suid = syscall.Getuid()

if err := syscall.Setuid(0); err != nil {
return 0, fmt.Errorf("failed to setuid 0: %w", err)
}

return suid, nil
func setupClientSysPrivileges() (int, error) {
return osutil.GainRoot()
}

func releaseClientSysPrivileges(suid int) error {
return syscall.Setuid(suid)
func releaseClientSysPrivileges(oldUID int) error {
return osutil.ReleaseRoot(oldUID)
}
7 changes: 4 additions & 3 deletions internal/vpn/os_client_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import (
"bytes"
"fmt"
"net"
"os/exec"
"sync"

"github.com/syndtr/gocapability/capability"
"golang.org/x/sys/unix"

"github.com/skycoin/skywire/pkg/util/osutil"
)

const (
Expand All @@ -19,9 +20,9 @@ const (

// DefaultNetworkGateway fetches system's default network gateway.
func DefaultNetworkGateway() (net.IP, error) {
outBytes, err := exec.Command("sh", "-c", defaultNetworkGatewayCMD).Output() //nolint:gosec
outBytes, err := osutil.RunWithResult("sh", "-c", defaultNetworkGatewayCMD)
if err != nil {
return nil, fmt.Errorf("error running command %s: %w", defaultNetworkGatewayCMD, err)
return nil, err
}

outBytes = bytes.TrimRight(outBytes, "\n")
Expand Down
9 changes: 4 additions & 5 deletions internal/vpn/os_client_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ package vpn

import (
"bytes"
"fmt"
"net"
"os/exec"
"regexp"

"github.com/skycoin/skywire/pkg/util/osutil"
)

const (
Expand All @@ -18,10 +18,9 @@ var redundantWhitespacesCleanupRegex = regexp.MustCompile(`[\s\p{Zs}]{2,}`)

// DefaultNetworkGateway fetches system's default network gateway.
func DefaultNetworkGateway() (net.IP, error) {
cmd := exec.Command("cmd", "/C", defaultNetworkGatewayCMD)
outBytes, err := cmd.Output() //nolint:gosec
outBytes, err := osutil.RunWithResult("cmd", "/C", defaultNetworkGatewayCMD)
if err != nil {
return nil, fmt.Errorf("error running command %s: %w", defaultNetworkGatewayCMD, err)
return nil, err
}

outBytes = bytes.TrimRight(outBytes, "\n\r")
Expand Down
8 changes: 5 additions & 3 deletions internal/vpn/os_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"fmt"
"strconv"
"strings"

"github.com/skycoin/skywire/pkg/util/osutil"
)

// SetupTUN sets the allocated TUN interface up, setting its IP, gateway, netmask and MTU.
Expand All @@ -16,7 +18,7 @@ func SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error {
return fmt.Errorf("error parsing IP CIDR: %w", err)
}

return run("ifconfig", ifcName, ip, gateway, "mtu", strconv.Itoa(mtu), "netmask", netmask, "up")
return osutil.Run("ifconfig", ifcName, ip, gateway, "mtu", strconv.Itoa(mtu), "netmask", netmask, "up")
}

// ChangeRoute changes current route to `ipCIDR` to go through the `gateway`
Expand All @@ -28,7 +30,7 @@ func ChangeRoute(ipCIDR, gateway string) error {
// AddRoute adds route to `ipCIDR` through the `gateway` to the OS routing table.
func AddRoute(ipCIDR, gateway string) error {
if err := modifyRoutingTable("add", ipCIDR, gateway); err != nil {
var e *ErrorWithStderr
var e *osutil.ErrorWithStderr
if errors.As(err, &e) {
if strings.Contains(string(e.Stderr), "File exists") {
return nil
Expand All @@ -52,5 +54,5 @@ func modifyRoutingTable(action, ipCIDR, gateway string) error {
return fmt.Errorf("error parsing IP CIDR: %w", err)
}

return run("route", action, "-net", ip, gateway, netmask)
return osutil.Run("route", action, "-net", ip, gateway, netmask)
}
16 changes: 9 additions & 7 deletions internal/vpn/os_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ import (
"fmt"
"strconv"
"strings"

"github.com/skycoin/skywire/pkg/util/osutil"
)

// SetupTUN sets the allocated TUN interface up, setting its IP, gateway, netmask and MTU.
func SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error {
if err := run("ip", "a", "add", ipCIDR, "dev", ifcName); err != nil {
if err := osutil.Run("ip", "a", "add", ipCIDR, "dev", ifcName); err != nil {
return fmt.Errorf("error assigning IP: %w", err)
}

if err := run("ip", "link", "set", "dev", ifcName, "mtu", strconv.Itoa(mtu)); err != nil {
if err := osutil.Run("ip", "link", "set", "dev", ifcName, "mtu", strconv.Itoa(mtu)); err != nil {
return fmt.Errorf("error setting MTU: %w", err)
}

Expand All @@ -24,7 +26,7 @@ func SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error {
return fmt.Errorf("error parsing IP CIDR: %w", err)
}

if err := run("ip", "link", "set", ifcName, "up"); err != nil {
if err := osutil.Run("ip", "link", "set", ifcName, "up"); err != nil {
return fmt.Errorf("error setting interface up: %w", err)
}

Expand All @@ -38,14 +40,14 @@ func SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error {
// ChangeRoute changes current route to `ip` to go through the `gateway`
// in the OS routing table.
func ChangeRoute(ip, gateway string) error {
return run("ip", "r", "change", ip, "via", gateway)
return osutil.Run("ip", "r", "change", ip, "via", gateway)
}

// AddRoute adds route to `ip` with `netmask` through the `gateway` to the OS routing table.
func AddRoute(ip, gateway string) error {
err := run("ip", "r", "add", ip, "via", gateway)
err := osutil.Run("ip", "r", "add", ip, "via", gateway)

var e *ErrorWithStderr
var e *osutil.ErrorWithStderr
if errors.As(err, &e) {
if strings.Contains(string(e.Stderr), "File exists") {
return nil
Expand All @@ -57,5 +59,5 @@ func AddRoute(ip, gateway string) error {

// DeleteRoute removes route to `ip` with `netmask` through the `gateway` from the OS routing table.
func DeleteRoute(ip, gateway string) error {
return run("ip", "r", "del", ip, "via", gateway)
return osutil.Run("ip", "r", "del", ip, "via", gateway)
}
59 changes: 15 additions & 44 deletions internal/vpn/os_server_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import (
"bytes"
"fmt"
"net"
"os/exec"
"strings"

"github.com/skycoin/skywire/pkg/util/osutil"
)

const (
Expand All @@ -26,9 +27,9 @@ const (

// GetIPTablesForwardPolicy gets current policy for iptables `forward` chain.
func GetIPTablesForwardPolicy() (string, error) {
outputBytes, err := exec.Command("sh", "-c", getIPTablesForwardPolicyCMD).Output()
outputBytes, err := osutil.RunWithResult("sh", "-c", getIPTablesForwardPolicyCMD)
if err != nil {
return "", fmt.Errorf("error running command %s: %w", getIPTablesForwardPolicyCMD, err)
return "", err
}

return strings.TrimRight(string(outputBytes), "\n"), nil
Expand All @@ -37,11 +38,7 @@ func GetIPTablesForwardPolicy() (string, error) {
// SetIPTablesForwardPolicy sets `policy` for iptables `forward` chain.
func SetIPTablesForwardPolicy(policy string) error {
cmd := fmt.Sprintf(setIPTablesForwardPolicyCMDFmt, policy)
if err := exec.Command("sh", "-c", cmd).Run(); err != nil { //nolint:gosec
return fmt.Errorf("error running command %s: %w", cmd, err)
}

return nil
return osutil.Run("sh", "-c", cmd)
}

// SetIPTablesForwardAcceptPolicy sets ACCEPT policy for iptables `forward` chain.
Expand All @@ -54,29 +51,21 @@ func SetIPTablesForwardAcceptPolicy() error {
// to private IP ranges.
func AllowIPToLocalNetwork(src, dst net.IP) error {
cmd := fmt.Sprintf(allowIPToLocalNetCMDFmt, src, src)
if err := exec.Command("sh", "-c", cmd).Run(); err != nil { //nolint:gosec
return fmt.Errorf("error running command %s: %w", cmd, err)
}

return nil
return osutil.Run("sh", "-c", cmd)
}

// BlockIPToLocalNetwork blocks all the packets coming from `source`
// to private IP ranges.
func BlockIPToLocalNetwork(src, dst net.IP) error {
cmd := fmt.Sprintf(blockIPToLocalNetCMDFmt, src, src)
if err := exec.Command("sh", "-c", cmd).Run(); err != nil { //nolint:gosec
return fmt.Errorf("error running command %s: %w", cmd, err)
}

return nil
return osutil.Run("sh", "-c", cmd)
}

// DefaultNetworkInterface fetches default network interface name.
func DefaultNetworkInterface() (string, error) {
outputBytes, err := exec.Command("sh", "-c", defaultNetworkInterfaceCMD).Output()
outputBytes, err := osutil.RunWithResult("sh", "-c", defaultNetworkInterfaceCMD)
if err != nil {
return "", fmt.Errorf("error running command %s: %w", defaultNetworkInterfaceCMD, err)
return "", err
}

// just in case
Expand All @@ -98,21 +87,13 @@ func GetIPv6ForwardingValue() (string, error) {
// SetIPv4ForwardingValue sets `val` value of IPv4 forwarding.
func SetIPv4ForwardingValue(val string) error {
cmd := fmt.Sprintf(setIPv4ForwardingCMDFmt, val)
if err := exec.Command("sh", "-c", cmd).Run(); err != nil { //nolint:gosec
return fmt.Errorf("error running command %s: %w", cmd, err)
}

return nil
return osutil.Run("sh", "-c", cmd)
}

// SetIPv6ForwardingValue sets `val` value of IPv6 forwarding.
func SetIPv6ForwardingValue(val string) error {
cmd := fmt.Sprintf(setIPv6ForwardingCMDFmt, val)
if err := exec.Command("sh", "-c", cmd).Run(); err != nil { //nolint:gosec
return fmt.Errorf("error running command %s: %w", cmd, err)
}

return nil
return osutil.Run("sh", "-c", cmd)
}

// EnableIPv4Forwarding enables IPv4 forwarding.
Expand All @@ -128,29 +109,19 @@ func EnableIPv6Forwarding() error {
// EnableIPMasquerading enables IP masquerading for the interface with name `ifcName`.
func EnableIPMasquerading(ifcName string) error {
cmd := fmt.Sprintf(enableIPMasqueradingCMDFmt, ifcName)
//nolint:gosec
if err := exec.Command("sh", "-c", cmd).Run(); err != nil {
return fmt.Errorf("error running command %s: %w", cmd, err)
}

return nil
return osutil.Run("sh", "-c", cmd)
}

// DisableIPMasquerading disables IP masquerading for the interface with name `ifcName`.
func DisableIPMasquerading(ifcName string) error {
cmd := fmt.Sprintf(disableIPMasqueradingCMDFmt, ifcName)
//nolint:gosec
if err := exec.Command("sh", "-c", cmd).Run(); err != nil {
return fmt.Errorf("error running command %s: %w", cmd, err)
}

return nil
return osutil.Run("sh", "-c", cmd)
}

func getIPForwardingValue(cmd string) (string, error) {
outBytes, err := exec.Command("sh", "-c", cmd).Output() //nolint:gosec
outBytes, err := osutil.RunWithResult("sh", "-c", cmd)
if err != nil {
return "", fmt.Errorf("error running command %s: %w", cmd, err)
return "", err
}

Darkren marked this conversation as resolved.
Show resolved Hide resolved
val, err := parseIPForwardingOutput(outBytes)
Expand Down
Loading