@ -126,6 +126,7 @@ type userspaceEngine struct {
sentActivityAt map [ netip . Addr ] * mono . Time // value is accessed atomically
sentActivityAt map [ netip . Addr ] * mono . Time // value is accessed atomically
destIPActivityFuncs map [ netip . Addr ] func ( )
destIPActivityFuncs map [ netip . Addr ] func ( )
lastStatusPollTime mono . Time // last time we polled the engine status
lastStatusPollTime mono . Time // last time we polled the engine status
reconfigureVPN func ( ) error // or nil
mu sync . Mutex // guards following; see lock order comment below
mu sync . Mutex // guards following; see lock order comment below
netMap * netmap . NetworkMap // or nil
netMap * netmap . NetworkMap // or nil
@ -175,6 +176,13 @@ type Config struct {
// If nil, a fake OSConfigurator that does nothing is used.
// If nil, a fake OSConfigurator that does nothing is used.
DNS dns . OSConfigurator
DNS dns . OSConfigurator
// ReconfigureVPN provides an optional hook for platforms like Android to
// know when it's time to reconfigure their VPN implementation. Such
// platforms can only set their entire VPN configuration (routes, DNS, etc)
// at all once and can't make piecemeal incremental changes, so this
// provides a hook to "flush" a batch of Router and/or DNS changes.
ReconfigureVPN func ( ) error
// NetMon optionally provides an existing network monitor to re-use.
// NetMon optionally provides an existing network monitor to re-use.
// If nil, a new network monitor is created.
// If nil, a new network monitor is created.
NetMon * netmon . Monitor
NetMon * netmon . Monitor
@ -283,6 +291,7 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
confListenPort : conf . ListenPort ,
confListenPort : conf . ListenPort ,
birdClient : conf . BIRDClient ,
birdClient : conf . BIRDClient ,
controlKnobs : conf . ControlKnobs ,
controlKnobs : conf . ControlKnobs ,
reconfigureVPN : conf . ReconfigureVPN ,
}
}
if e . birdClient != nil {
if e . birdClient != nil {
@ -956,6 +965,9 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
if err != nil {
if err != nil {
return err
return err
}
}
if err := e . reconfigureVPNIfNecessary ( ) ; err != nil {
return err
}
}
}
// Shutdown the network logger.
// Shutdown the network logger.
@ -1161,10 +1173,12 @@ func (e *userspaceEngine) linkChange(delta *netmon.ChangeDelta) {
}
}
}
}
// Hacky workaround for Linu x DNS issue 2458: on
// Hacky workaround for Uni x DNS issue 2458: on
// suspend/resume or whenever NetworkManager is started, it
// suspend/resume or whenever NetworkManager is started, it
// nukes all systemd-resolved configs. So reapply our DNS
// nukes all systemd-resolved configs. So reapply our DNS
// config on major link change.
// config on major link change.
// TODO: explain why this is ncessary not just on Linux but also android
// and Apple platforms.
if changed {
if changed {
switch runtime . GOOS {
switch runtime . GOOS {
case "linux" , "android" , "ios" , "darwin" :
case "linux" , "android" , "ios" , "darwin" :
@ -1174,6 +1188,8 @@ func (e *userspaceEngine) linkChange(delta *netmon.ChangeDelta) {
if dnsCfg != nil {
if dnsCfg != nil {
if err := e . dns . Set ( * dnsCfg ) ; err != nil {
if err := e . dns . Set ( * dnsCfg ) ; err != nil {
e . logf ( "wgengine: error setting DNS config after major link change: %v" , err )
e . logf ( "wgengine: error setting DNS config after major link change: %v" , err )
} else if err := e . reconfigureVPNIfNecessary ( ) ; err != nil {
e . logf ( "wgengine: error reconfiguring VPN after major link change: %v" , err )
} else {
} else {
e . logf ( "wgengine: set DNS config again after major link change" )
e . logf ( "wgengine: set DNS config again after major link change" )
}
}
@ -1528,3 +1544,10 @@ func (e *userspaceEngine) InstallCaptureHook(cb capture.Callback) {
e . tundev . InstallCaptureHook ( cb )
e . tundev . InstallCaptureHook ( cb )
e . magicConn . InstallCaptureHook ( cb )
e . magicConn . InstallCaptureHook ( cb )
}
}
func ( e * userspaceEngine ) reconfigureVPNIfNecessary ( ) error {
if e . reconfigureVPN == nil {
return nil
}
return e . reconfigureVPN ( )
}