From 73e536690fe910e6f36db337fd844034f0c84d02 Mon Sep 17 00:00:00 2001 From: MohammadReza Palide Date: Wed, 29 Jun 2022 12:07:30 +0430 Subject: [PATCH 1/6] fix cap problem --- internal/vpn/client.go | 94 ++++++--------------------------- internal/vpn/os_client_linux.go | 55 +++++++++---------- internal/vpn/os_darwin.go | 8 +-- internal/vpn/os_linux.go | 91 +++++++++++++++++++++++++++++-- internal/vpn/os_windows.go | 8 +-- internal/vpn/server.go | 2 +- 6 files changed, 135 insertions(+), 123 deletions(-) diff --git a/internal/vpn/client.go b/internal/vpn/client.go index 05f0d78d0..ee8386a6b 100644 --- a/internal/vpn/client.go +++ b/internal/vpn/client.go @@ -129,46 +129,27 @@ func NewClient(cfg ClientConfig, appCl *app.Client) (*Client, error) { // Serve dials VPN server, sets up TUN and establishes VPN session. func (c *Client) Serve() error { c.setAppStatus(launcher.AppDetailedStatusStarting) - if err := c.setSysPrivileges(); err != nil { - c.setAppError(err) - return fmt.Errorf("failed to setup system privileges: %w", err) - } // we setup direct routes to skywire services once for all the client lifetime since routes don't change. // but if they change, new routes get delivered to the app via callbacks. if err := c.setupDirectRoutes(); err != nil { - c.releaseSysPrivileges() c.setAppError(err) return fmt.Errorf("error setting up direct routes: %w", err) } - c.releaseSysPrivileges() defer func() { - if err := c.setSysPrivileges(); err != nil { - fmt.Printf("failed to setup system privileges: %v\n", err) - return - } - defer c.releaseSysPrivileges() - c.removeDirectRoutes() }() // we call this preliminary, so it will be called on app stop defer func() { if c.cfg.Killswitch { - err := c.setSysPrivileges() - if err != nil { - print(fmt.Sprintf("Error setting up system privileges: %v\n", err)) - } else { - c.prevTUNGatewayMu.Lock() - if len(c.prevTUNGateway) > 0 { - fmt.Printf("Routing traffic directly, previous TUN gateway: %s\n", c.prevTUNGateway.String()) - c.routeTrafficDirectly(c.prevTUNGateway) - } - c.prevTUNGateway = nil - c.prevTUNGatewayMu.Unlock() - - c.releaseSysPrivileges() + c.prevTUNGatewayMu.Lock() + if len(c.prevTUNGateway) > 0 { + fmt.Printf("Routing traffic directly, previous TUN gateway: %s\n", c.prevTUNGateway.String()) + c.routeTrafficDirectly(c.prevTUNGateway) } + c.prevTUNGateway = nil + c.prevTUNGatewayMu.Unlock() } if err := c.closeTUN(); err != nil { @@ -264,22 +245,12 @@ func (c *Client) AddDirectRoute(ip net.IP) error { c.directIPs = append(c.directIPs, ip) - if err := c.setSysPrivileges(); err != nil { - return fmt.Errorf("failed to setup system privileges: %w", err) - } - defer c.releaseSysPrivileges() - return c.setupDirectRoute(ip) } func (c *Client) removeDirectRouteFn(ip net.IP, i int) error { c.directIPs = append(c.directIPs[:i], c.directIPs[i+1:]...) - if err := c.setSysPrivileges(); err != nil { - return fmt.Errorf("failed to setup system privileges: %w", err) - } - defer c.releaseSysPrivileges() - return c.removeDirectRoute(ip) } @@ -301,24 +272,6 @@ func (c *Client) RemoveDirectRoute(ip net.IP) error { return nil } -func (c *Client) setSysPrivileges() error { - if runtime.GOOS != "windows" { - c.suidMu.Lock() - - // we don't release the lock here to avoid races, - // lock will be released after reverting system privileges - - suid, err := setupClientSysPrivileges() - if err != nil { - return err - } - - c.suid = suid - } - - return nil -} - func (c *Client) createTUN() (TUNDevice, error) { c.tunMu.Lock() defer c.tunMu.Unlock() @@ -359,7 +312,7 @@ func (c *Client) setupTUN(tunIP, tunGateway net.IP) error { return errors.New("TUN is not created") } - return SetupTUN(c.tun.Name(), tunIP.String()+TUNNetmaskCIDR, tunGateway.String(), TUNMTU) + return c.SetupTUN(c.tun.Name(), tunIP.String()+TUNNetmaskCIDR, tunGateway.String(), TUNMTU) } func (c *Client) serveConn(conn net.Conn) error { @@ -373,17 +326,6 @@ func (c *Client) serveConn(conn net.Conn) error { fmt.Printf("Local TUN IP: %s\n", tunIP.String()) fmt.Printf("Local TUN gateway: %s\n", tunGateway.String()) - if err := c.setSysPrivileges(); err != nil { - return fmt.Errorf("failed to setup system privileges: %w", err) - } - - // this call is important. it will either run on an error down the line, - // or, in case VPN sessions finishes, it will be the last call in deferred stack, - // releasing system privileges after cleanup - defer func() { - c.releaseSysPrivileges() - }() - fmt.Println("CREATING TUN INTERFACE") tun, err := c.createTUN() if err != nil { @@ -439,7 +381,6 @@ func (c *Client) serveConn(conn net.Conn) error { }() // we release privileges here (user is not root for Mac OS systems from here on) - c.releaseSysPrivileges() connToTunDoneCh := make(chan struct{}) tunToConnCh := make(chan struct{}) @@ -483,11 +424,6 @@ serveLoop: } } - // here we setup system privileges again, so deferred calls may be done safely - if err := c.setSysPrivileges(); err != nil { - print(fmt.Sprintf("Failed to setup system privileges for cleanup: %v\n", err)) - } - return nil } @@ -521,17 +457,17 @@ func (c *Client) dialServeConn() error { func (c *Client) routeTrafficThroughTUN(tunGateway net.IP, isNewRoute bool) error { // route all traffic through TUN gateway if isNewRoute { - if err := AddRoute(ipv4FirstHalfAddr, tunGateway.String()); err != nil { + if err := c.AddRoute(ipv4FirstHalfAddr, tunGateway.String()); err != nil { return err } - if err := AddRoute(ipv4SecondHalfAddr, tunGateway.String()); err != nil { + if err := c.AddRoute(ipv4SecondHalfAddr, tunGateway.String()); err != nil { return err } } else { - if err := ChangeRoute(ipv4FirstHalfAddr, tunGateway.String()); err != nil { + if err := c.ChangeRoute(ipv4FirstHalfAddr, tunGateway.String()); err != nil { return err } - if err := ChangeRoute(ipv4SecondHalfAddr, tunGateway.String()); err != nil { + if err := c.ChangeRoute(ipv4SecondHalfAddr, tunGateway.String()); err != nil { return err } } @@ -543,10 +479,10 @@ func (c *Client) routeTrafficDirectly(tunGateway net.IP) { fmt.Println("Routing all traffic through default network gateway") // remove main route - if err := DeleteRoute(ipv4FirstHalfAddr, tunGateway.String()); err != nil { + if err := c.DeleteRoute(ipv4FirstHalfAddr, tunGateway.String()); err != nil { print(fmt.Sprintf("Error routing traffic through default network gateway: %v\n", err)) } - if err := DeleteRoute(ipv4SecondHalfAddr, tunGateway.String()); err != nil { + if err := c.DeleteRoute(ipv4SecondHalfAddr, tunGateway.String()); err != nil { print(fmt.Sprintf("Error routing traffic through default network gateway: %v\n", err)) } } @@ -567,7 +503,7 @@ func (c *Client) setupDirectRoutes() error { func (c *Client) setupDirectRoute(ip net.IP) error { if !ip.IsLoopback() { fmt.Printf("Adding direct route to %s, via %s\n", ip.String(), c.defaultGateway.String()) - if err := AddRoute(ip.String()+directRouteNetmaskCIDR, c.defaultGateway.String()); err != nil { + if err := c.AddRoute(ip.String()+directRouteNetmaskCIDR, c.defaultGateway.String()); err != nil { return fmt.Errorf("error adding direct route to %s: %w", ip.String(), err) } } @@ -578,7 +514,7 @@ func (c *Client) setupDirectRoute(ip net.IP) error { func (c *Client) removeDirectRoute(ip net.IP) error { if !ip.IsLoopback() { fmt.Printf("Removing direct route to %s\n", ip.String()) - if err := DeleteRoute(ip.String()+directRouteNetmaskCIDR, c.defaultGateway.String()); err != nil { + if err := c.DeleteRoute(ip.String()+directRouteNetmaskCIDR, c.defaultGateway.String()); err != nil { return err } } diff --git a/internal/vpn/os_client_linux.go b/internal/vpn/os_client_linux.go index a613dd555..6123db6ca 100644 --- a/internal/vpn/os_client_linux.go +++ b/internal/vpn/os_client_linux.go @@ -7,7 +7,6 @@ import ( "bytes" "fmt" "net" - "sync" "github.com/syndtr/gocapability/capability" "golang.org/x/sys/unix" @@ -45,42 +44,38 @@ func DefaultNetworkGateway() (net.IP, error) { return nil, errCouldFindDefaultNetworkGateway } -var setupClientOnce sync.Once - func setupClientSysPrivileges() (int, error) { var 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 - } + var caps capability.Capabilities - err = caps.Load() - if err != nil { - err = fmt.Errorf("failed to load capabilities: %w", err) - return - } + caps, err = capability.NewPid2(0) + if err != nil { + err = fmt.Errorf("failed to init capabilities: %w", err) + return 0, err + } - // set `CAP_NET_ADMIN` capability to needed caps sets. - caps.Set(capability.CAPS|capability.BOUNDS|capability.AMBIENT, capability.CAP_NET_ADMIN) - err = caps.Apply(capability.CAPS | capability.BOUNDS | capability.AMBIENT) - if err != nil { - err = fmt.Errorf("failed to apply capabilties: %w", err) + err = caps.Load() + if err != nil { + err = fmt.Errorf("failed to load capabilities: %w", err) + return 0, err + } - return - } + // set `CAP_NET_ADMIN` capability to needed caps sets. + caps.Set(capability.CAPS|capability.BOUNDS|capability.AMBIENT, capability.CAP_NET_ADMIN) + err = caps.Apply(capability.CAPS | capability.BOUNDS | capability.AMBIENT) + if err != nil { + err = fmt.Errorf("failed to apply capabilties: %w", err) + return 0, err + } - // let child process keep caps sets from the parent, so we may do calls to - // system utilities with these caps. - err = unix.Prctl(unix.PR_SET_KEEPCAPS, 1, 0, 0, 0) - if err != nil { - err = fmt.Errorf("failed to set PR_SET_KEEPCAPS: %w", err) - return - } - }) + // let child process keep caps sets from the parent, so we may do calls to + // system utilities with these caps. + err = unix.Prctl(unix.PR_SET_KEEPCAPS, 1, 0, 0, 0) + if err != nil { + err = fmt.Errorf("failed to set PR_SET_KEEPCAPS: %w", err) + return 0, err + } return 0, nil } diff --git a/internal/vpn/os_darwin.go b/internal/vpn/os_darwin.go index c22c7b250..9944bb339 100644 --- a/internal/vpn/os_darwin.go +++ b/internal/vpn/os_darwin.go @@ -13,7 +13,7 @@ import ( ) // SetupTUN sets the allocated TUN interface up, setting its IP, gateway, netmask and MTU. -func SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error { +func (c *Client) SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error { ip, netmask, err := parseCIDR(ipCIDR) if err != nil { return fmt.Errorf("error parsing IP CIDR: %w", err) @@ -24,12 +24,12 @@ func SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error { // ChangeRoute changes current route to `ipCIDR` to go through the `gateway` // in the OS routing table. -func ChangeRoute(ipCIDR, gateway string) error { +func (c *Client) ChangeRoute(ipCIDR, gateway string) error { return modifyRoutingTable("change", ipCIDR, gateway) } // AddRoute adds route to `ipCIDR` through the `gateway` to the OS routing table. -func AddRoute(ipCIDR, gateway string) error { +func (c *Client) AddRoute(ipCIDR, gateway string) error { if err := modifyRoutingTable("add", ipCIDR, gateway); err != nil { var e *osutil.ErrorWithStderr if errors.As(err, &e) { @@ -45,7 +45,7 @@ func AddRoute(ipCIDR, gateway string) error { } // DeleteRoute removes route to `ipCIDR` through the `gateway` from the OS routing table. -func DeleteRoute(ipCIDR, gateway string) error { +func (c *Client) DeleteRoute(ipCIDR, gateway string) error { return modifyRoutingTable("delete", ipCIDR, gateway) } diff --git a/internal/vpn/os_linux.go b/internal/vpn/os_linux.go index 37caaa00f..38412003a 100644 --- a/internal/vpn/os_linux.go +++ b/internal/vpn/os_linux.go @@ -6,32 +6,41 @@ package vpn import ( "errors" "fmt" + "runtime" "strconv" "strings" "github.com/skycoin/skywire/pkg/util/osutil" ) +// Client + // SetupTUN sets the allocated TUN interface up, setting its IP, gateway, netmask and MTU. -func SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error { +func (c *Client) SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error { + c.setSysPrivileges() if err := osutil.Run("ip", "a", "add", ipCIDR, "dev", ifcName); err != nil { return fmt.Errorf("error assigning IP: %w", err) } + c.releaseSysPrivileges() + c.setSysPrivileges() if err := osutil.Run("ip", "link", "set", "dev", ifcName, "mtu", strconv.Itoa(mtu)); err != nil { return fmt.Errorf("error setting MTU: %w", err) } + c.releaseSysPrivileges() ip, _, err := parseCIDR(ipCIDR) if err != nil { return fmt.Errorf("error parsing IP CIDR: %w", err) } + c.setSysPrivileges() if err := osutil.Run("ip", "link", "set", ifcName, "up"); err != nil { return fmt.Errorf("error setting interface up: %w", err) } + c.releaseSysPrivileges() - if err := AddRoute(ip, gateway); err != nil { + if err := c.AddRoute(ip, gateway); err != nil { return fmt.Errorf("error setting gateway for interface: %w", err) } @@ -40,12 +49,16 @@ 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 { +func (c *Client) ChangeRoute(ip, gateway string) error { + c.setSysPrivileges() + defer c.releaseSysPrivileges() 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 { +func (c *Client) AddRoute(ip, gateway string) error { + c.setSysPrivileges() + defer c.releaseSysPrivileges() err := osutil.Run("ip", "r", "add", ip, "via", gateway) var e *osutil.ErrorWithStderr @@ -65,6 +78,74 @@ 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 { +func (c *Client) DeleteRoute(ip, gateway string) error { + c.setSysPrivileges() + defer c.releaseSysPrivileges() return osutil.Run("ip", "r", "del", ip, "via", gateway) } + +func (c *Client) setSysPrivileges() error { + if runtime.GOOS != "windows" { + c.suidMu.Lock() + + // we don't release the lock here to avoid races, + // lock will be released after reverting system privileges + + suid, err := setupClientSysPrivileges() + if err != nil { + return err + } + + c.suid = suid + } + + return nil +} + +// Server + +// SetupTUN sets the allocated TUN interface up, setting its IP, gateway, netmask and MTU. +func (s *Server) SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error { + if err := osutil.Run("ip", "a", "add", ipCIDR, "dev", ifcName); err != nil { + return fmt.Errorf("error assigning IP: %w", err) + } + + if err := osutil.Run("ip", "link", "set", "dev", ifcName, "mtu", strconv.Itoa(mtu)); err != nil { + return fmt.Errorf("error setting MTU: %w", err) + } + + ip, _, err := parseCIDR(ipCIDR) + if err != nil { + return fmt.Errorf("error parsing IP CIDR: %w", err) + } + + if err := osutil.Run("ip", "link", "set", ifcName, "up"); err != nil { + return fmt.Errorf("error setting interface up: %w", err) + } + + if err := s.AddRoute(ip, gateway); err != nil { + return fmt.Errorf("error setting gateway for interface: %w", err) + } + + return nil +} + +// AddRoute adds route to `ip` with `netmask` through the `gateway` to the OS routing table. +func (s *Server) AddRoute(ip, gateway string) error { + err := osutil.Run("ip", "r", "add", ip, "via", gateway) + + var e *osutil.ErrorWithStderr + if errors.As(err, &e) { + if strings.Contains(string(e.Stderr), "File exists") { + return nil + } + } + + if errors.As(err, &e) { + if strings.Contains(string(e.Stderr), "Operation not permitted") { + return errPermissionDenied + } + } + + return err +} diff --git a/internal/vpn/os_windows.go b/internal/vpn/os_windows.go index af4e819ef..76462b5f0 100644 --- a/internal/vpn/os_windows.go +++ b/internal/vpn/os_windows.go @@ -16,7 +16,7 @@ const ( ) // SetupTUN sets the allocated TUN interface up, setting its IP, gateway, netmask and MTU. -func SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error { +func (c *Client) SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error { ip, netmask, err := parseCIDR(ipCIDR) if err != nil { return fmt.Errorf("error parsing IP CIDR: %w", err) @@ -37,17 +37,17 @@ func SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error { // ChangeRoute changes current route to `ipCIDR` to go through the `gateway` // in the OS routing table. -func ChangeRoute(ipCIDR, gateway string) error { +func (c *Client) ChangeRoute(ipCIDR, gateway string) error { return modifyRoutingTable("change", ipCIDR, gateway) } // AddRoute adds route to `ipCIDR` through the `gateway` to the OS routing table. -func AddRoute(ipCIDR, gateway string) error { +func (c *Client) AddRoute(ipCIDR, gateway string) error { return modifyRoutingTable("add", ipCIDR, gateway) } // DeleteRoute removes route to `ipCIDR` through the `gateway` from the OS routing table. -func DeleteRoute(ipCIDR, gateway string) error { +func (c *Client) DeleteRoute(ipCIDR, gateway string) error { return modifyRoutingTable("delete", ipCIDR, gateway) } diff --git a/internal/vpn/server.go b/internal/vpn/server.go index 4d9ab7dec..04d78d400 100644 --- a/internal/vpn/server.go +++ b/internal/vpn/server.go @@ -234,7 +234,7 @@ func (s *Server) serveConn(conn net.Conn) { fmt.Printf("Allocated TUN %s", tun.Name()) - if err := SetupTUN(tun.Name(), tunIP.String()+TUNNetmaskCIDR, tunGateway.String(), TUNMTU); err != nil { + if err := s.SetupTUN(tun.Name(), tunIP.String()+TUNNetmaskCIDR, tunGateway.String(), TUNMTU); err != nil { print(fmt.Sprintf("Error setting up TUN %s: %v", tun.Name(), err)) return } From 126c31796c50bbd0869aff180fe318cdf7165e8b Mon Sep 17 00:00:00 2001 From: MohammadReza Palide Date: Wed, 29 Jun 2022 12:19:20 +0430 Subject: [PATCH 2/6] make check && make format --- internal/vpn/os.go | 2 +- internal/vpn/os_linux.go | 30 ++++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/internal/vpn/os.go b/internal/vpn/os.go index 10868c67e..03f788c1b 100644 --- a/internal/vpn/os.go +++ b/internal/vpn/os.go @@ -5,7 +5,7 @@ import ( "net" ) -func parseCIDR(ipCIDR string) (ipStr, netmask string, err error) { +func parseCIDR(ipCIDR string) (ipStr, netmask string, err error) { //nolint : actually used in os_windows.go ip, net, err := net.ParseCIDR(ipCIDR) if err != nil { return "", "", err diff --git a/internal/vpn/os_linux.go b/internal/vpn/os_linux.go index 38412003a..01a404cc4 100644 --- a/internal/vpn/os_linux.go +++ b/internal/vpn/os_linux.go @@ -17,13 +17,19 @@ import ( // SetupTUN sets the allocated TUN interface up, setting its IP, gateway, netmask and MTU. func (c *Client) SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error { - c.setSysPrivileges() + if err := c.setSysPrivileges(); err != nil { + print(fmt.Sprintf("Failed to setup system privileges for SetupTUN: %v\n", err)) + return err + } if err := osutil.Run("ip", "a", "add", ipCIDR, "dev", ifcName); err != nil { return fmt.Errorf("error assigning IP: %w", err) } c.releaseSysPrivileges() - c.setSysPrivileges() + if err := c.setSysPrivileges(); err != nil { + print(fmt.Sprintf("Failed to setup system privileges for SetupTUN: %v\n", err)) + return err + } if err := osutil.Run("ip", "link", "set", "dev", ifcName, "mtu", strconv.Itoa(mtu)); err != nil { return fmt.Errorf("error setting MTU: %w", err) } @@ -34,7 +40,10 @@ func (c *Client) SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error { return fmt.Errorf("error parsing IP CIDR: %w", err) } - c.setSysPrivileges() + if err := c.setSysPrivileges(); err != nil { + print(fmt.Sprintf("Failed to setup system privileges for SetupTUN: %v\n", err)) + return err + } if err := osutil.Run("ip", "link", "set", ifcName, "up"); err != nil { return fmt.Errorf("error setting interface up: %w", err) } @@ -50,14 +59,20 @@ func (c *Client) 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 (c *Client) ChangeRoute(ip, gateway string) error { - c.setSysPrivileges() + if err := c.setSysPrivileges(); err != nil { + print(fmt.Sprintf("Failed to setup system privileges for ChangeRoute: %v\n", err)) + return err + } defer c.releaseSysPrivileges() 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 (c *Client) AddRoute(ip, gateway string) error { - c.setSysPrivileges() + if err := c.setSysPrivileges(); err != nil { + print(fmt.Sprintf("Failed to setup system privileges for AddRoute: %v\n", err)) + return err + } defer c.releaseSysPrivileges() err := osutil.Run("ip", "r", "add", ip, "via", gateway) @@ -79,7 +94,10 @@ func (c *Client) AddRoute(ip, gateway string) error { // DeleteRoute removes route to `ip` with `netmask` through the `gateway` from the OS routing table. func (c *Client) DeleteRoute(ip, gateway string) error { - c.setSysPrivileges() + if err := c.setSysPrivileges(); err != nil { + print(fmt.Sprintf("Failed to setup system privileges for DeleteRoute: %v\n", err)) + return err + } defer c.releaseSysPrivileges() return osutil.Run("ip", "r", "del", ip, "via", gateway) } From d01711ddba392dcf62b767e381d968a864949508 Mon Sep 17 00:00:00 2001 From: MohammadReza Palide Date: Wed, 29 Jun 2022 08:07:47 +0430 Subject: [PATCH 3/6] fix windows problem --- internal/vpn/os_windows.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/internal/vpn/os_windows.go b/internal/vpn/os_windows.go index 76462b5f0..7a945ce20 100644 --- a/internal/vpn/os_windows.go +++ b/internal/vpn/os_windows.go @@ -60,3 +60,23 @@ func modifyRoutingTable(action, ipCIDR, gateway string) error { cmd := fmt.Sprintf(modifyRouteCMDFmt, action, ip, netmask, gateway) return osutil.Run("cmd", "/C", cmd) } + +// SetupTUN sets the allocated TUN interface up, setting its IP, gateway, netmask and MTU. +func (s *Server) SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error { + ip, netmask, err := parseCIDR(ipCIDR) + if err != nil { + return fmt.Errorf("error parsing IP CIDR: %w", err) + } + + setupCmd := fmt.Sprintf(tunSetupCMDFmt, ifcName, ip, netmask, gateway) + if err := osutil.Run("cmd", "/C", setupCmd); err != nil { + return fmt.Errorf("error running command %s: %w", setupCmd, err) + } + + mtuSetupCmd := fmt.Sprintf(tunMTUSetupCMDFmt, ifcName, mtu) + if err := osutil.Run("cmd", "/C", mtuSetupCmd); err != nil { + return fmt.Errorf("error running command %s: %w", mtuSetupCmd, err) + } + + return nil +} From c70368c11979ed98da31cf4f5ee073c50e8d09aa Mon Sep 17 00:00:00 2001 From: MohammadReza Palide Date: Wed, 29 Jun 2022 08:09:40 +0430 Subject: [PATCH 4/6] fix darwin issue --- internal/vpn/os_darwin.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/internal/vpn/os_darwin.go b/internal/vpn/os_darwin.go index 9944bb339..c0f4744b1 100644 --- a/internal/vpn/os_darwin.go +++ b/internal/vpn/os_darwin.go @@ -57,3 +57,12 @@ func modifyRoutingTable(action, ipCIDR, gateway string) error { return osutil.Run("route", action, "-net", ip, gateway, netmask) } + +func (s *Server) SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error { + ip, netmask, err := parseCIDR(ipCIDR) + if err != nil { + return fmt.Errorf("error parsing IP CIDR: %w", err) + } + + return osutil.Run("ifconfig", ifcName, ip, gateway, "mtu", strconv.Itoa(mtu), "netmask", netmask, "up") +} From 35d707123eb23ed3bb0f472c2b4205344991f36c Mon Sep 17 00:00:00 2001 From: MohammadReza Palide Date: Wed, 29 Jun 2022 13:26:51 +0430 Subject: [PATCH 5/6] fix darwin check --- internal/vpn/client.go | 18 ++++++++++++++++++ internal/vpn/client_unix.go | 2 +- internal/vpn/os_darwin.go | 21 ++++++++++++++++----- internal/vpn/os_linux.go | 19 ------------------- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/internal/vpn/client.go b/internal/vpn/client.go index ee8386a6b..78c6fbb26 100644 --- a/internal/vpn/client.go +++ b/internal/vpn/client.go @@ -272,6 +272,24 @@ func (c *Client) RemoveDirectRoute(ip net.IP) error { return nil } +func (c *Client) setSysPrivileges() error { // nolint: just use on + if runtime.GOOS != "windows" { + c.suidMu.Lock() + + // we don't release the lock here to avoid races, + // lock will be released after reverting system privileges + + suid, err := setupClientSysPrivileges() + if err != nil { + return err + } + + c.suid = suid + } + + return nil +} + func (c *Client) createTUN() (TUNDevice, error) { c.tunMu.Lock() defer c.tunMu.Unlock() diff --git a/internal/vpn/client_unix.go b/internal/vpn/client_unix.go index fbf38688e..0d4409d62 100644 --- a/internal/vpn/client_unix.go +++ b/internal/vpn/client_unix.go @@ -5,7 +5,7 @@ package vpn import "fmt" -func (c *Client) releaseSysPrivileges() { +func (c *Client) releaseSysPrivileges() { // nolint: just use on os_linux.go defer c.suidMu.Unlock() if err := releaseClientSysPrivileges(c.suid); err != nil { diff --git a/internal/vpn/os_darwin.go b/internal/vpn/os_darwin.go index c0f4744b1..9f9152f7b 100644 --- a/internal/vpn/os_darwin.go +++ b/internal/vpn/os_darwin.go @@ -18,19 +18,24 @@ func (c *Client) SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error { if err != nil { return fmt.Errorf("error parsing IP CIDR: %w", err) } - + if err := c.setSysPrivileges(); err != nil { + print(fmt.Sprintf("Failed to setup system privileges for SetupTUN: %v\n", err)) + return err + } + defer c.releaseSysPrivileges() 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` // in the OS routing table. func (c *Client) ChangeRoute(ipCIDR, gateway string) error { - return modifyRoutingTable("change", ipCIDR, gateway) + return c.modifyRoutingTable("change", ipCIDR, gateway) } // AddRoute adds route to `ipCIDR` through the `gateway` to the OS routing table. func (c *Client) AddRoute(ipCIDR, gateway string) error { - if err := modifyRoutingTable("add", ipCIDR, gateway); err != nil { + if err := c.modifyRoutingTable("add", ipCIDR, gateway); err != nil { var e *osutil.ErrorWithStderr if errors.As(err, &e) { if strings.Contains(string(e.Stderr), "File exists") { @@ -46,18 +51,24 @@ func (c *Client) AddRoute(ipCIDR, gateway string) error { // DeleteRoute removes route to `ipCIDR` through the `gateway` from the OS routing table. func (c *Client) DeleteRoute(ipCIDR, gateway string) error { - return modifyRoutingTable("delete", ipCIDR, gateway) + return c.modifyRoutingTable("delete", ipCIDR, gateway) } -func modifyRoutingTable(action, ipCIDR, gateway string) error { +func (c *Client) modifyRoutingTable(action, ipCIDR, gateway string) error { ip, netmask, err := parseCIDR(ipCIDR) if err != nil { return fmt.Errorf("error parsing IP CIDR: %w", err) } + if err := c.setSysPrivileges(); err != nil { + print(fmt.Sprintf("Failed to setup system privileges for %s: %v\n", action, err)) + return err + } + defer c.releaseSysPrivileges() return osutil.Run("route", action, "-net", ip, gateway, netmask) } +// SetupTUN sets the allocated TUN interface up, setting its IP, gateway, netmask and MTU. func (s *Server) SetupTUN(ifcName, ipCIDR, gateway string, mtu int) error { ip, netmask, err := parseCIDR(ipCIDR) if err != nil { diff --git a/internal/vpn/os_linux.go b/internal/vpn/os_linux.go index 01a404cc4..6bc94314a 100644 --- a/internal/vpn/os_linux.go +++ b/internal/vpn/os_linux.go @@ -6,7 +6,6 @@ package vpn import ( "errors" "fmt" - "runtime" "strconv" "strings" @@ -102,24 +101,6 @@ func (c *Client) DeleteRoute(ip, gateway string) error { return osutil.Run("ip", "r", "del", ip, "via", gateway) } -func (c *Client) setSysPrivileges() error { - if runtime.GOOS != "windows" { - c.suidMu.Lock() - - // we don't release the lock here to avoid races, - // lock will be released after reverting system privileges - - suid, err := setupClientSysPrivileges() - if err != nil { - return err - } - - c.suid = suid - } - - return nil -} - // Server // SetupTUN sets the allocated TUN interface up, setting its IP, gateway, netmask and MTU. From c2bb79895f3bffbefc590a63dbde938b790d220a Mon Sep 17 00:00:00 2001 From: MohammadReza Palide Date: Wed, 29 Jun 2022 14:02:58 +0430 Subject: [PATCH 6/6] fix windows check --- internal/vpn/client.go | 6 +++--- internal/vpn/client_unix.go | 2 +- internal/vpn/client_windows.go | 3 --- internal/vpn/os_client_windows.go | 2 +- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/internal/vpn/client.go b/internal/vpn/client.go index 78c6fbb26..fba7352b5 100644 --- a/internal/vpn/client.go +++ b/internal/vpn/client.go @@ -43,8 +43,8 @@ type Client struct { prevTUNGateway net.IP prevTUNGatewayMu sync.Mutex - suidMu sync.Mutex - suid int + suidMu sync.Mutex //nolint + suid int //nolint tunMu sync.Mutex tun TUNDevice @@ -272,7 +272,7 @@ func (c *Client) RemoveDirectRoute(ip net.IP) error { return nil } -func (c *Client) setSysPrivileges() error { // nolint: just use on +func (c *Client) setSysPrivileges() error { //nolint if runtime.GOOS != "windows" { c.suidMu.Lock() diff --git a/internal/vpn/client_unix.go b/internal/vpn/client_unix.go index 0d4409d62..b776a22d3 100644 --- a/internal/vpn/client_unix.go +++ b/internal/vpn/client_unix.go @@ -5,7 +5,7 @@ package vpn import "fmt" -func (c *Client) releaseSysPrivileges() { // nolint: just use on os_linux.go +func (c *Client) releaseSysPrivileges() { // nolint defer c.suidMu.Unlock() if err := releaseClientSysPrivileges(c.suid); err != nil { diff --git a/internal/vpn/client_windows.go b/internal/vpn/client_windows.go index 3fac9cd9c..7f3e5c475 100644 --- a/internal/vpn/client_windows.go +++ b/internal/vpn/client_windows.go @@ -2,6 +2,3 @@ // +build windows package vpn - -func (c *Client) releaseSysPrivileges() { -} diff --git a/internal/vpn/os_client_windows.go b/internal/vpn/os_client_windows.go index fe990d285..057da38d6 100644 --- a/internal/vpn/os_client_windows.go +++ b/internal/vpn/os_client_windows.go @@ -51,6 +51,6 @@ func DefaultNetworkGateway() (net.IP, error) { return nil, errCouldFindDefaultNetworkGateway } -func setupClientSysPrivileges() (suid int, err error) { +func setupClientSysPrivileges() (suid int, err error) { //nolint return 0, nil }