Skip to content

Commit

Permalink
Merge branch 'development' into beta
Browse files Browse the repository at this point in the history
  • Loading branch information
stenya committed Nov 15, 2023
2 parents d1d5603 + b6c182b commit e68b4fd
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 7 deletions.
5 changes: 4 additions & 1 deletion daemon/netchange/net_change_detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,14 @@ func (d *Detector) Stop() error {
return nil
}

// must be called when routing change detected (called from platform-specific sources)
// Must be called when routing change detected (called from platform-specific sources)
// It notifies about routing change with delay 'd.DelayBeforeNotify()'. This reduces amount of multiple consecutive notifications
func (d *Detector) routingChangeDetected() {
d.timerNotifyAfterDelay.Reset(d.delayBeforeNotify)
}

// Immediately notify about routing change.
// Consider using routingChangeDetected() instead
func (d *Detector) notifyRoutingChange() {
if d.routingChangeNotifyChan == nil {
return
Expand Down
2 changes: 1 addition & 1 deletion daemon/netchange/net_change_detector_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func (d *Detector) doStart() {
}

// notify about routing change
d.notifyRoutingChange()
d.routingChangeDetected()
}
}

Expand Down
111 changes: 106 additions & 5 deletions daemon/v2r/v2ray.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,12 @@ type V2RayWrapper struct {
mutex sync.Mutex
stoppedChan chan struct{}

routeStatusMutex sync.Mutex
// IP address of the default gateway which was used for static route to V2Ray server
defaultGeteway net.IP
// IP address of local interface which is in use for communication with V2Ray server
// (we use use it to detect changes of the route to V2Ray server)
localInterfaceIp net.IP
}

// CreateV2RayWrapper - creates new V2RayWrapper object
Expand Down Expand Up @@ -157,13 +161,42 @@ func (v *V2RayWrapper) UpdateMainRoute() error {
v.mutex.Lock()
defer v.mutex.Unlock()

var curDefaultGeteway net.IP
var curLocalInterfaceIp net.IP
func() {
// lock access to defaultGeteway and localInterfaceIp
v.routeStatusMutex.Lock()
defer v.routeStatusMutex.Unlock()
curDefaultGeteway = v.defaultGeteway
curLocalInterfaceIp = v.localInterfaceIp
}()

// check: do we need to update route to V2Ray server? (due to it was changed or removed)
isRouteChanged := false
if curLocalInterfaceIp != nil {
if lInterfaceIp, err := v.getMainRouteLocalInfAddress(); err == nil {
if !curLocalInterfaceIp.Equal(lInterfaceIp) {
isRouteChanged = true
}
}
}

if !isRouteChanged && curDefaultGeteway == nil {
return nil
}

// check: do we need to update route to V2Ray server? (due to change of default gateway)
isGatewayChanged := false
gwIp, err := netinfo.DefaultGatewayIP()
if err != nil {
return fmt.Errorf("getting default gateway ip error : %w", err)
return fmt.Errorf("failed to check V2Ray route consistency: %w", err)
}
if !curDefaultGeteway.Equal(gwIp) {
isGatewayChanged = true
}

if v.defaultGeteway != nil && v.defaultGeteway.Equal(gwIp) {
return nil //gateway did not chnage. Nothing to update
if !isGatewayChanged && !isRouteChanged {
return nil // nothing to update
}

log.Info("Updating route to V2Ray server...")
Expand All @@ -182,13 +215,28 @@ func (v *V2RayWrapper) setMainRoute(defaultGateway net.IP) error {
}
}
if err := v.implSetMainRoute(defaultGateway); err == nil {
// lock access to defaultGeteway and localInterfaceIp
v.routeStatusMutex.Lock()
defer v.routeStatusMutex.Unlock()

v.defaultGeteway = defaultGateway
// save IP address of local interface which is in use for communication with V2Ray server
v.localInterfaceIp, err = v.getMainRouteLocalInfAddress()
if err != nil {
return fmt.Errorf("unable to obtain local interface info for V2Ray connection: %w", err)
}
}
return err
}

func (v *V2RayWrapper) deleteMainRoute() error {
v.defaultGeteway = nil
func() {
// lock access to defaultGeteway and localInterfaceIp
v.routeStatusMutex.Lock()
defer v.routeStatusMutex.Unlock()
v.defaultGeteway = nil
v.localInterfaceIp = nil
}()
return v.implDeleteMainRoute()
}

Expand Down Expand Up @@ -323,8 +371,29 @@ func (v *V2RayWrapper) start() (retError error) {
return startError
}

// log when process finished
// routine alive until process finished
go func() {

// Periodically checking the IP address of the local interface used for communication with the V2Ray server
// and update/restore route, if necessary
done := make(chan struct{}, 1)
defer close(done)
go func() {
for {
select {
case <-time.After(time.Second * 20):
if v.isMainRouteLocalInfAddressChanged() {
log.Info("The IP address of the local interface used for communication with the V2Ray server has changed")
if err := v.UpdateMainRoute(); err != nil {
log.Error(err)
}
}
case <-done:
return
}
}
}()

v.command.Wait()
// ensure route is deleted
v.implDeleteMainRoute()
Expand All @@ -334,3 +403,35 @@ func (v *V2RayWrapper) start() (retError error) {
log.Info(fmt.Sprintf("V2Ray client started (port %s)", configuredPortStr))
return nil
}

func (v *V2RayWrapper) isMainRouteLocalInfAddressChanged() bool {
var curLocalInterfaceIp net.IP
func() {
// lock access to defaultGeteway and localInterfaceIp
v.routeStatusMutex.Lock()
defer v.routeStatusMutex.Unlock()
curLocalInterfaceIp = v.localInterfaceIp
}()

if curLocalInterfaceIp == nil {
return false
}

// check: do we need to update route to V2Ray server? (due to it was changed or removed)
if lInterfaceIp, err := v.getMainRouteLocalInfAddress(); err == nil {
if !curLocalInterfaceIp.Equal(lInterfaceIp) {
return true
}
}
return false
}

// Get IP address of local interface which is in use for communication with V2Ray server
// (it depends of routing table)
func (v *V2RayWrapper) getMainRouteLocalInfAddress() (net.IP, error) {
remoteHost, _, err := v.getRemoteEndpoint()
if err != nil {
return nil, err
}
return netinfo.GetOutboundIPEx(remoteHost)
}

0 comments on commit e68b4fd

Please sign in to comment.