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

fixing VPN server problem with multiple network interface #1156

Merged
merged 7 commits into from
Apr 25, 2022
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
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 @@ -30,6 +30,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 @@ -43,6 +43,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 @@ -200,6 +201,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 @@ -411,6 +412,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 @@ -604,13 +604,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 @@ -661,6 +662,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