Skip to content

Conversation

hakansa
Copy link
Member

@hakansa hakansa commented Aug 19, 2025

Implement a background watcher that restarts the engine when the WireGuard interface is created or deleted. This addition enhances the engines resilience to external changes in the interface state.

Describe your changes

Issue ticket number and link

Stack

Checklist

  • Is it a bug fix
  • Is a typo/documentation fix
  • Is a feature enhancement
  • It is a refactor
  • Created tests that fail without the change (if possible)

By submitting this pull request, you confirm that you have read and agree to the terms of the Contributor License Agreement.

Documentation

Select exactly one:

  • I added/updated documentation for this change
  • Documentation is not needed for this change (explain why):
    Internal change

Docs PR URL (required if "docs added" is checked)

Paste the PR link from https://github.com/netbirdio/docs here:

https://github.com/netbirdio/docs/pull/__

Implement a background watcher that restarts the engine when the WireGuard interface is created or deleted. This addition enhances the engine's resilience to external changes in the interface state.
Refine the background watcher to handle interface lifecycle changes more accurately. The monitor now skips execution on mobile platforms and tracks interface recreation by comparing indices, improving the engine's response to external interface modifications.
@hakansa hakansa marked this pull request as ready for review August 22, 2025 05:13
@Copilot Copilot AI review requested due to automatic review settings August 22, 2025 05:13
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Implements a WireGuard interface lifecycle monitoring system that automatically restarts the engine when the WireGuard interface is externally deleted or recreated, improving the client's resilience to interface state changes.

  • Adds background monitoring of WireGuard interface using polling approach
  • Tracks interface index changes to detect recreation scenarios
  • Implements cross-platform solution with mobile platform exclusions

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

ifi, err := net.InterfaceByName(name)
if err != nil {
// Check if it's specifically a "not found" error
if errors.Is(err, &net.OpError{}) {
Copy link
Preview

Copilot AI Aug 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error check errors.Is(err, &net.OpError{}) is incorrect. errors.Is compares error values, not types. Use var opErr *net.OpError; errors.As(err, &opErr) to check if the error is of type *net.OpError.

Suggested change
if errors.Is(err, &net.OpError{}) {
var opErr *net.OpError
if errors.As(err, &opErr) {

Copilot uses AI. Check for mistakes.

go func(ctx context.Context, ifaceName string, expectedIndex int) {
log.Infof("Interface monitor: watching %s (index: %d)", ifaceName, expectedIndex)

ticker := time.NewTicker(2 * time.Second)
Copy link
Preview

Copilot AI Aug 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The polling interval of 2 seconds is a magic number that should be made configurable or defined as a named constant for better maintainability and potential tuning.

Suggested change
ticker := time.NewTicker(2 * time.Second)
ticker := time.NewTicker(wgIfaceMonitorPollInterval)

Copilot uses AI. Check for mistakes.

…nagement

Add a new WGIfaceMonitor to manage the WireGuard interface lifecycle, allowing the engine to respond to interface deletions and recreations. This implementation replaces the previous monitoring method, improving reliability and maintaining compatibility with mobile platforms.
// It relies on the provided context cancellation to stop.
func (m *WGIfaceMonitor) Start(ifaceName string) {
// Skip on mobile platforms as they handle interface lifecycle differently
if runtime.GOOS == "android" || runtime.GOOS == "ios" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd probably put this check in the code calling NewWGIfaceMonitor() instead of here, it's not the Monitor's concern whether it should run or not, especially when you're already passing an unspecified callback function.

}

// Stop stops the monitor and waits for the goroutine to exit.
func (m *WGIfaceMonitor) Stop() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you run Stop and m.retartEngine() at the same time, then it can cause a deadlock for 5 sec because both of them use the same mutex in the engine.

Copy link

sonarqubecloud bot commented Sep 18, 2025

Quality Gate Passed Quality Gate passed

Issues
0 New issues
2 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarQube Cloud

@hakansa hakansa merged commit 644ed4b into main Sep 25, 2025
34 of 35 checks passed
@hakansa hakansa deleted the feat/wg-iface-monitor branch September 25, 2025 08:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants