Skip to content

Commit

Permalink
Merge pull request #1156 from mrpalide/fix/vpn-server-multiple-device…
Browse files Browse the repository at this point in the history
…-issue

fixing VPN server problem with multiple network interface
  • Loading branch information
ersonp authored Apr 25, 2022
2 parents 964433d + 47b7fac commit 61b62a8
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 10 deletions.
22 changes: 20 additions & 2 deletions .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,30 @@ environment:
appveyor_build_worker_image: ubuntu2004

for:
- # Linux and MacOS
- # Linux
skip_tags: true
matrix:
only:
- job_name: Linux

install:
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.2
- sudo apt-get install gcc libgtk-3-dev libayatana-appindicator3-dev -y
- make dep
- sh: ci_scripts/create-ip-aliases.sh

before_build:
- make check

build_script:
- make build
- make build-systray

- # MacOS
skip_tags: true
matrix:
only:
- job_name: Linux
- job_name: MacOS

install:
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.44.2
Expand Down
6 changes: 4 additions & 2 deletions cmd/apps/vpn-server/vpn-server.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ var (
localPKStr = flag.String("pk", "", "Local PubKey")
localSKStr = flag.String("sk", "", "Local SecKey")
passcode = flag.String("passcode", "", "Passcode to authenticate connecting users")
networkIfc = flag.String("netifc", "", "Default network interface for multiple available interfaces")
secure = flag.Bool("secure", true, "Forbid connections from clients to server local network")
)

Expand Down Expand Up @@ -73,8 +74,9 @@ func main() {
log.Infof("Got app listener, bound to %d", vpnPort)

srvCfg := vpn.ServerConfig{
Passcode: *passcode,
Secure: *secure,
Passcode: *passcode,
Secure: *secure,
NetworkInterface: *networkIfc,
}
srv, err := vpn.NewServer(srvCfg, log)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions cmd/skywire-cli/commands/config/update/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ var (
addVPNServerPasscode string
setVPNServerSecure string
setVPNServerAutostart string
setVPNServerNetIfc string
resetVPNServer bool
addSkysocksClientSrv string
resetSkysocksClient bool
Expand Down
4 changes: 4 additions & 0 deletions cmd/skywire-cli/commands/config/update/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func init() {
vpnServerUpdateCmd.Flags().StringVarP(&addVPNServerPasscode, "passwd", "s", "", "add passcode to vpn-server")
vpnServerUpdateCmd.Flags().StringVar(&setVPNServerSecure, "secure", "", "change secure mode status of vpn-server")
vpnServerUpdateCmd.Flags().StringVar(&setVPNServerAutostart, "autostart", "", "change autostart of vpn-server")
vpnServerUpdateCmd.Flags().StringVar(&setVPNServerNetIfc, "netifc", "", "set default network interface")
vpnServerUpdateCmd.Flags().BoolVarP(&resetVPNServer, "reset", "r", false, "reset vpn-server configurations")
}

Expand Down Expand Up @@ -160,6 +161,9 @@ var vpnServerUpdateCmd = &cobra.Command{
if addVPNServerPasscode != "" {
changeAppsConfig(conf, "vpn-server", "--passcode", addVPNServerPasscode)
}
if setVPNServerNetIfc != "" {
changeAppsConfig(conf, "vpn-server", "--netifc", setVPNServerNetIfc)
}
switch setVPNServerSecure {
case "true":
changeAppsConfig(conf, "vpn-server", "--secure", setVPNServerSecure)
Expand Down
4 changes: 2 additions & 2 deletions internal/gui/gui.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func initAdvancedButton(conf *visorconfig.V1) {
// if it's not installed via package, hide the uninstall button
initUninstallBtn()
//hide the buttons which could launch the browser if the process is run as root
if checkRoot() {
if isRoot() {
mAdvancedButton.Hide()
mOpenHypervisor.Hide()
return
Expand Down Expand Up @@ -178,7 +178,7 @@ func initAdvancedButton(conf *visorconfig.V1) {

func initOpenVPNLinkBtn(vc *visorconfig.V1) {
mVPNLink = systray.AddMenuItem("Open VPN UI", "Open VPN UI in browser")
if checkRoot() {
if isRoot() {
mVPNLink.Hide()
return
}
Expand Down
32 changes: 31 additions & 1 deletion internal/vpn/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"io"
"net"
"strings"
"sync"

"github.com/sirupsen/logrus"
Expand All @@ -29,16 +30,28 @@ type Server struct {

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

defaultNetworkIfc, err := netutil.DefaultNetworkInterface()
defaultNetworkIfcs, err := netutil.DefaultNetworkInterface()
if err != nil {
return nil, fmt.Errorf("error getting default network interface: %w", err)
}
ifcs, hasMultiple := s.hasMutipleNetworkInterfaces(defaultNetworkIfcs)
if hasMultiple {
if cfg.NetworkInterface == "" {
return nil, fmt.Errorf("multiple default network interfaces detected...set a default one for VPN server or remove one: %v", ifcs)
} else if !s.validateInterface(ifcs, cfg.NetworkInterface) {
return nil, fmt.Errorf("network interface value in config is not in default network interfaces detected: %v", ifcs)
}
defaultNetworkIfc = cfg.NetworkInterface
} else {
defaultNetworkIfc = defaultNetworkIfcs
}

l.Infof("Got default network interface: %s", defaultNetworkIfc)

Expand Down Expand Up @@ -316,3 +329,20 @@ func (s *Server) sendServerErrHello(conn net.Conn, status HandshakeStatus) {
s.log.WithError(err).Errorln("Error sending server hello")
}
}

func (s *Server) hasMutipleNetworkInterfaces(defaultNetworkInterface string) ([]string, bool) {
networkInterfaces := strings.Split(defaultNetworkInterface, "\n")
if len(networkInterfaces) > 1 {
return networkInterfaces, true
}
return []string{}, false
}

func (s *Server) validateInterface(ifcs []string, selectedIfc string) bool {
for _, ifc := range ifcs {
if ifc == selectedIfc {
return true
}
}
return false
}
5 changes: 3 additions & 2 deletions internal/vpn/server_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package vpn

// ServerConfig is a configuration for VPN server.
type ServerConfig struct {
Passcode string
Secure bool
Passcode string
Secure bool
NetworkInterface string
}
22 changes: 22 additions & 0 deletions pkg/visor/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type API interface {
SetAppPK(appName string, pk cipher.PubKey) error
SetAppSecure(appName string, isSecure bool) error
SetAppKillswitch(appName string, killswitch bool) error
SetAppNetworkInterface(appName string, netifc string) error
LogsSince(timestamp time.Time, appName string) ([]string, error)
GetAppStats(appName string) (appserver.AppStats, error)
GetAppError(appName string) (string, error)
Expand Down Expand Up @@ -410,6 +411,27 @@ func (v *Visor) SetAppPassword(appName, password string) error {
return nil
}

// SetAppNetworkInterface implements API.
func (v *Visor) SetAppNetworkInterface(appName, netifc string) error {
if skyenv.VPNServerName != appName {
return fmt.Errorf("app %s is not allowed to set network interface", appName)
}

v.log.Infof("Changing %s network interface to %q", appName, netifc)

const (
netifcArgName = "--netifc"
)

if err := v.conf.UpdateAppArg(v.appL, appName, netifcArgName, netifc); err != nil {
return err
}

v.log.Infof("Updated %v network interface", appName)

return nil
}

// SetAppKillswitch implements API.
func (v *Visor) SetAppKillswitch(appName string, killswitch bool) error {
if appName != skyenv.VPNClientName {
Expand Down
10 changes: 9 additions & 1 deletion pkg/visor/hypervisor.go
Original file line number Diff line number Diff line change
Expand Up @@ -612,13 +612,14 @@ func (hv *Hypervisor) putApp() http.HandlerFunc {
Secure *bool `json:"secure,omitempty"`
Status *int `json:"status,omitempty"`
Passcode *string `json:"passcode,omitempty"`
NetIfc *string `json:"netifc,omitempty"`
PK *cipher.PubKey `json:"pk,omitempty"`
}

shouldRestartApp := func(r req) bool {
// we restart the app if one of these fields was changed
return r.Killswitch != nil || r.Secure != nil || r.Passcode != nil ||
r.PK != nil
r.PK != nil || r.NetIfc != nil
}

var reqBody req
Expand Down Expand Up @@ -669,6 +670,13 @@ func (hv *Hypervisor) putApp() http.HandlerFunc {
}
}

if reqBody.NetIfc != nil {
if err := ctx.API.SetAppNetworkInterface(ctx.App.Name, *reqBody.NetIfc); err != nil {
httputil.WriteJSON(w, r, http.StatusInternalServerError, err)
return
}
}

if shouldRestartApp(reqBody) {
if err := ctx.API.RestartApp(ctx.App.Name); err != nil {
httputil.WriteJSON(w, r, http.StatusInternalServerError, err)
Expand Down
13 changes: 13 additions & 0 deletions pkg/visor/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,19 @@ func (r *RPC) SetAppPassword(in *SetAppPasswordIn, _ *struct{}) (err error) {
return r.visor.SetAppPassword(in.AppName, in.Password)
}

// SetAppNetworkInterfaceIn is input for SetAppNetworkInterface.
type SetAppNetworkInterfaceIn struct {
AppName string
NetIfc string
}

// SetAppNetworkInterface sets network interface for the app.
func (r *RPC) SetAppNetworkInterface(in *SetAppNetworkInterfaceIn, _ *struct{}) (err error) {
defer rpcutil.LogCall(r.log, "SetAppNetworkInterface", in)(nil, &err)

return r.visor.SetAppNetworkInterface(in.AppName, in.NetIfc)
}

// SetAppPKIn is input for SetAppPK.
type SetAppPKIn struct {
AppName string
Expand Down
23 changes: 23 additions & 0 deletions pkg/visor/rpc_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,14 @@ func (rc *rpcClient) SetAppKillswitch(appName string, killswitch bool) error {
}, &struct{}{})
}

// SetAppKillswitch implements API.
func (rc *rpcClient) SetAppNetworkInterface(appName, netifc string) error {
return rc.Call("SetAppNetworkInterface", &SetAppNetworkInterfaceIn{
AppName: appName,
NetIfc: netifc,
}, &struct{}{})
}

// SetAppSecure implements API.
func (rc *rpcClient) SetAppSecure(appName string, isSecure bool) error {
return rc.Call("SetAppSecure", &SetAppBoolIn{
Expand Down Expand Up @@ -743,6 +751,21 @@ func (mc *mockRPCClient) SetAppPassword(string, string) error {
})
}

// SetAppPassword implements API.
func (mc *mockRPCClient) SetAppNetworkInterface(string, string) error {
return mc.do(true, func() error {
const vpnServerName = "vpn-server"

for i := range mc.o.Apps {
if mc.o.Apps[i].Name == vpnServerName {
return nil
}
}

return fmt.Errorf("app of name '%s' does not exist", vpnServerName)
})
}

// SetAppPK implements API.
func (mc *mockRPCClient) SetAppPK(string, cipher.PubKey) error {
return mc.do(true, func() error {
Expand Down

0 comments on commit 61b62a8

Please sign in to comment.