diff --git a/client/internal/engine.go b/client/internal/engine.go index 416dfd318..86331ea3c 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -2452,6 +2452,8 @@ func (e *Engine) GetWgV6Addr() netip.Addr { return e.wgInterface.Address().IPv6 } +// RenewTun swaps the tunnel device for the one behind fd, which the platform +// hands over whenever it re-establishes the interface. func (e *Engine) RenewTun(fd int) error { e.syncMsgMux.Lock() wgInterface := e.wgInterface @@ -2461,7 +2463,12 @@ func (e *Engine) RenewTun(fd int) error { return fmt.Errorf("wireguard interface not initialized") } - return wgInterface.RenewTun(fd) + if err := wgInterface.RenewTun(fd); err != nil { + return err + } + + e.restartFileDrop() + return nil } // updateDNSForwarder start or stop the DNS forwarder based on the domains and the feature flag diff --git a/client/internal/engine_filedrop.go b/client/internal/engine_filedrop.go index 50b49f209..734fdf52f 100644 --- a/client/internal/engine_filedrop.go +++ b/client/internal/engine_filedrop.go @@ -103,6 +103,22 @@ func (e *Engine) setFileDropTunnel() { e.fileDrop.SetTunnel(dial, e.statusRecorder.GetLocalPeerState().FQDN) } +// restartFileDrop rebinds the receiver after the platform replaced the tunnel +// device. The listeners are bound to the overlay address of the interface being +// swapped out and do not survive it: Android renews the tun on every route +// change, which leaves the IPv4 listener dead with accept4: invalid argument. +func (e *Engine) restartFileDrop() { + e.syncMsgMux.Lock() + defer e.syncMsgMux.Unlock() + + if e.fileDrop == nil || !e.fileDropRunning || e.wgInterface == nil { + return + } + + e.stopFileDrop() + e.startFileDrop() +} + func (e *Engine) stopFileDrop() { if e.fileDrop == nil { return