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

Run vpn server non root #535

Merged
merged 7 commits into from
Oct 12, 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
40 changes: 22 additions & 18 deletions internal/vpn/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,14 @@ const (

// Client is a VPN client.
type Client struct {
cfg ClientConfig
log logrus.FieldLogger
conn net.Conn
directIPSMu sync.Mutex
directIPs []net.IP
defaultGateway net.IP
sysPrivilegesMx sync.Mutex
closeC chan struct{}
closeOnce sync.Once
cfg ClientConfig
log logrus.FieldLogger
conn net.Conn
directIPSMu sync.Mutex
directIPs []net.IP
defaultGateway net.IP
closeC chan struct{}
closeOnce sync.Once
}

// NewClient creates VPN client instance.
Expand Down Expand Up @@ -112,7 +111,7 @@ func (c *Client) AddDirectRoute(ip net.IP) error {

c.directIPs = append(c.directIPs, ip)

suid, err := c.setupSysPrivileges()
suid, err := setupClientSysPrivileges()
if err != nil {
return fmt.Errorf("failed to setup system privileges: %w", err)
}
Expand Down Expand Up @@ -156,7 +155,7 @@ func (c *Client) Serve() error {
c.log.Infof("Local TUN IP: %s", tunIP.String())
c.log.Infof("Local TUN gateway: %s", tunGateway.String())

suid, err := c.setupSysPrivileges()
suid, err := setupClientSysPrivileges()
if err != nil {
return fmt.Errorf("failed to setup system privileges: %w", err)
}
Expand Down Expand Up @@ -200,8 +199,13 @@ func (c *Client) Serve() error {
return fmt.Errorf("error routing traffic through TUN %s: %w", tun.Name(), err)
}

// we release privileges here (user is not root for Mac OS systems from here on)suid
// we release privileges here (user is not root for Mac OS systems from here on)
c.releaseSysPrivileges(suid)
// this will be executed first on return, so we setup privileges once again,
// so other deferred clear up calls may be done successfully
if _, err := setupClientSysPrivileges(); err != nil {
c.log.WithError(err).Errorln("Failed to setup system privileges to clear up")
}

connToTunDoneCh := make(chan struct{})
tunToConnCh := make(chan struct{})
Expand All @@ -228,12 +232,6 @@ func (c *Client) Serve() error {
case <-c.closeC:
}

// we setup system privileges again here, so that the deferred call could perform clean up
suid, err = c.setupSysPrivileges()
if err != nil {
c.log.WithError(err).Errorln("Failed to setup system privileges for clean up")
}

return nil
}

Expand Down Expand Up @@ -447,6 +445,12 @@ func (c *Client) shakeHands() (TUNIP, TUNGateway net.IP, err error) {
return sHello.TUNIP, sHello.TUNGateway, nil
}

func (c *Client) releaseSysPrivileges(suid int) {
if err := releaseClientSysPrivileges(suid); err != nil {
c.log.WithError(err).Errorln("Failed to release system privileges")
}
}

func ipFromEnv(key string) (net.IP, error) {
ip, ok, err := IPFromEnv(key)
if err != nil {
Expand Down
28 changes: 0 additions & 28 deletions internal/vpn/client_darwin.go

This file was deleted.

53 changes: 0 additions & 53 deletions internal/vpn/client_linux.go

This file was deleted.

22 changes: 22 additions & 0 deletions internal/vpn/os_client_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"fmt"
"net"
"os/exec"
"sync"
"syscall"
)

const (
Expand Down Expand Up @@ -36,3 +38,23 @@ func DefaultNetworkGateway() (net.IP, error) {

return nil, errCouldFindDefaultNetworkGateway
}

var clientSysPrivilegesMx sync.Mutex

func setupClientSysPrivileges() (suid int, err error) {
clientSysPrivilegesMx.Lock()

suid = syscall.Getuid()

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

return suid, nil
}

func releaseClientSysPrivileges(suid int) error {
err := syscall.Setuid(suid)
clientSysPrivilegesMx.Unlock()
return err
}
44 changes: 44 additions & 0 deletions internal/vpn/os_client_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import (
"fmt"
"net"
"os/exec"
"sync"

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

const (
Expand Down Expand Up @@ -38,3 +42,43 @@ func DefaultNetworkGateway() (net.IP, error) {

return nil, errCouldFindDefaultNetworkGateway
}

var setupClientOnce sync.Once

func setupClientSysPrivileges() (suid int, err error) {
setupClientOnce.Do(func() {
var caps capability.Capabilities

caps, err = capability.NewPid2(0)
if err != nil {
err = fmt.Errorf("failed to init capabilities: %w", err)
return
}

err = caps.Load()
if err != nil {
err = fmt.Errorf("failed to load capabilities: %w", err)
return
}

// set `CAP_NET_ADMIN` capability to needed caps sets.
caps.Set(capability.CAPS|capability.BOUNDS|capability.AMBIENT, capability.CAP_NET_ADMIN)
if err := caps.Apply(capability.CAPS | capability.BOUNDS | capability.AMBIENT); err != nil {
err = fmt.Errorf("failed to apply capabilties: %w", err)
return
}

// let child process keep caps sets from the parent, so we may do calls to
// system utilities with these caps.
if err := unix.Prctl(unix.PR_SET_KEEPCAPS, 1, 0, 0, 0); err != nil {
err = fmt.Errorf("failed to set PR_SET_KEEPCAPS: %w", err)
return
}
})

return 0, nil
}

func releaseClientSysPrivileges(_ int) error {
return nil
}
8 changes: 8 additions & 0 deletions internal/vpn/os_client_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,11 @@ func DefaultNetworkGateway() (net.IP, error) {

return nil, errCouldFindDefaultNetworkGateway
}

func setupSysPrivileges() (suid int, err error) {
return 0, nil
}

func releaseSysPrivileges(suid int) {
return
}
6 changes: 0 additions & 6 deletions internal/vpn/os_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package vpn
import (
"fmt"
"strconv"
"syscall"
)

// SetupTUN sets the allocated TUN interface up, setting its IP, gateway, netmask and MTU.
Expand Down Expand Up @@ -37,8 +36,3 @@ func DeleteRoute(ipCIDR, gateway string) error {

return run("route", "delete", "-net", ip, gateway, netmask)
}

// Setuid sets uid of current OS user.
func Setuid(uid int) error {
return syscall.Setuid(uid)
}
7 changes: 0 additions & 7 deletions internal/vpn/os_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,3 @@ func DeleteRoute(ipCIDR, gateway string) error {
cmd := fmt.Sprintf(deleteRouteCMDFmt, ip, netmask, gateway)
return run("cmd", "/C", cmd)
}

// Setuid sets uid of current OS user.
func Setuid(_ int) (err error) {
// this is unsupported yet, but we allow app to be run with super user,
// so no privilege escalation, and no error here.
return nil
}
19 changes: 11 additions & 8 deletions internal/vpn/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ type Server struct {

// NewServer creates VPN server instance.
func NewServer(cfg ServerConfig, l logrus.FieldLogger) (*Server, error) {
s := &Server{
cfg: cfg,
log: l,
ipGen: NewIPGenerator(),
}

defaultNetworkIfc, err := DefaultNetworkInterface()
if err != nil {
return nil, fmt.Errorf("error getting default network interface: %w", err)
Expand All @@ -44,14 +50,11 @@ func NewServer(cfg ServerConfig, l logrus.FieldLogger) (*Server, error) {
l.Infoln("Old IP forwarding values:")
l.Infof("IPv4: %s, IPv6: %s", ipv4ForwardingVal, ipv6ForwardingVal)

return &Server{
cfg: cfg,
log: l,
ipGen: NewIPGenerator(),
defaultNetworkInterface: defaultNetworkIfc,
ipv4ForwardingVal: ipv4ForwardingVal,
ipv6ForwardingVal: ipv6ForwardingVal,
}, nil
s.defaultNetworkInterface = defaultNetworkIfc
s.ipv4ForwardingVal = ipv4ForwardingVal
s.ipv6ForwardingVal = ipv6ForwardingVal

return s, nil
}

// Serve accepts connections from `l` and serves them.
Expand Down