Skip to content

[client] Android - Create the Android fake IP manager lazily on DNS flag enable - #6989

Open
pappz wants to merge 1 commit into
mainfrom
fix/android-lazy-fake-ip-manager
Open

[client] Android - Create the Android fake IP manager lazily on DNS flag enable#6989
pappz wants to merge 1 commit into
mainfrom
fix/android-lazy-fake-ip-manager

Conversation

@pappz

@pappz pappz commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Describe your changes

The fake IP manager was only created at route manager construction, from the DNS feature flag fetched by the initial GetNetworkMap call. When the flag flipped to true mid-session, UpdateRoutes set useNewDNSRoute but never created the manager, so domain routes added after the flip got a DNS interceptor with a nil fake IP manager.

internalDnatFw only checked for a firewall and GOOS, so the interceptor took the DNAT path and called GetFakeIP/AllocateFakeIP on the nil *fakeip.Manager. These methods lock m.mu first, which is a nil pointer dereference: the first DNS answer for such a route panicked and crashed the VPN service. The fake IP blocks (240.0.0.0/8 and its v6 pair) also never reached the TUN, since only the constructor registered them.

Create the manager and its TUN routes from UpdateRoutes when the flag turns on, notify so the fake IP blocks get into the TUN without a client route change, and treat a nil manager as no internal DNAT.

This is groundwork for removing the initial GetNetworkMap fetch, after which every startup goes through the flag-off-to-on transition.

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)
  • This change does not modify the public API, gRPC protocols, functionality behavior, CLI / service flags, or introduce a new feature — OR I have discussed it with the NetBird team beforehand (link the issue / Slack thread in the description). See CONTRIBUTING.md.

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)

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/__

Summary by CodeRabbit

  • Bug Fixes
    • Improved Android routing behavior when fake-IP support is unavailable or not yet initialized.
    • Fake-IP routes are now enabled only when the relevant Android DNS setting is active.
    • Network changes are now refreshed when fake-IP routes are configured.

The fake IP manager was only created at route manager construction,
from the DNS feature flag fetched by the initial GetNetworkMap call.
When the flag flipped to true mid-session, UpdateRoutes set
useNewDNSRoute but never created the manager, so domain routes added
after the flip got a DNS interceptor with a nil fake IP manager.

internalDnatFw only checked for a firewall and GOOS, so the interceptor
took the DNAT path and called GetFakeIP/AllocateFakeIP on the nil
*fakeip.Manager. These methods lock m.mu first, which is a nil pointer
dereference: the first DNS answer for such a route panicked and crashed
the VPN service. The fake IP blocks (240.0.0.0/8 and its v6 pair) also
never reached the TUN, since only the constructor registered them.

Create the manager and its TUN routes from UpdateRoutes when the flag
turns on, notify so the fake IP blocks get into the TUN without a
client route change, and treat a nil manager as no internal DNAT.

This is groundwork for removing the initial GetNetworkMap fetch, after
which every startup goes through the flag-off-to-on transition.
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Android fake-IP route creation is now conditional and reusable during setup and runtime route updates. The Android notifier emits a network-change notification when fake routes are assigned, and internal DNAT requires an initialized fake-IP manager.

Changes

Android fake-IP route lifecycle

Layer / File(s) Summary
Fake-IP route setup and notification
client/internal/routemanager/manager.go, client/internal/routemanager/notifier/notifier_android.go
Android setup conditionally creates IPv4 and IPv6 fake routes through enableFakeIPRoutes, stores the fake-IP manager, and notifies listeners when routes are assigned.
Runtime initialization and DNAT guard
client/internal/routemanager/manager.go, client/internal/routemanager/dnsinterceptor/handler.go
UpdateRoutes initializes fake-IP routes when the new Android DNS route is enabled and no manager exists; internal DNAT now also requires a non-nil fake-IP manager.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: lixmal

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: lazy creation of the Android fake IP manager when the DNS flag turns on.
Description check ✅ Passed The description follows the template and explains the change well; only the issue ticket and stack sections are left blank.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/android-lazy-fake-ip-manager

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@client/internal/routemanager/manager.go`:
- Around line 472-474: Publish fake-IP route changes only after the complete
route state is committed: in client/internal/routemanager/manager.go:472-474
defer notification until the normal route update has committed currentRoutes;
initialize the notifier route state before its first notification at
manager.go:168-171; separate fake-route assignment from notification at
manager.go:194-195; and in
client/internal/routemanager/notifier/notifier_android.go:42-44 serialize or
coalesce callbacks so notifications occur only with a complete, ordered
snapshot.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6332cc31-a676-43f4-9bb2-55bf2d21b193

📥 Commits

Reviewing files that changed from the base of the PR and between c1f0006 and 75905a9.

📒 Files selected for processing (3)
  • client/internal/routemanager/dnsinterceptor/handler.go
  • client/internal/routemanager/manager.go
  • client/internal/routemanager/notifier/notifier_android.go

Comment on lines +472 to +474
if runtime.GOOS == "android" && useNewDNSRoute && m.fakeIPManager == nil {
m.enableFakeIPRoutes()
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Publish fake-IP route changes only after the complete route state is committed.

The current flow emits an intermediate snapshot before initial/current routes are installed, and asynchronous callbacks can arrive out of order, potentially leaving the TUN with stale or missing routes.

  • client/internal/routemanager/manager.go#L472-L474: defer notification until the normal route update has committed currentRoutes.
  • client/internal/routemanager/manager.go#L168-L171: initialize the notifier’s route state before the first notification.
  • client/internal/routemanager/manager.go#L194-L195: separate fake-route assignment from notification.
  • client/internal/routemanager/notifier/notifier_android.go#L42-L44: serialize or coalesce callbacks, or notify only after the full snapshot is ready.
📍 Affects 2 files
  • client/internal/routemanager/manager.go#L472-L474 (this comment)
  • client/internal/routemanager/manager.go#L168-L171
  • client/internal/routemanager/manager.go#L194-L195
  • client/internal/routemanager/notifier/notifier_android.go#L42-L44
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/internal/routemanager/manager.go` around lines 472 - 474, Publish
fake-IP route changes only after the complete route state is committed: in
client/internal/routemanager/manager.go:472-474 defer notification until the
normal route update has committed currentRoutes; initialize the notifier route
state before its first notification at manager.go:168-171; separate fake-route
assignment from notification at manager.go:194-195; and in
client/internal/routemanager/notifier/notifier_android.go:42-44 serialize or
coalesce callbacks so notifications occur only with a complete, ordered
snapshot.

@github-actions

Copy link
Copy Markdown

Release artifacts

Built for PR head 75905a9 in workflow run #17304.

Artifact Link
All release artifacts Download
Linux packages Download
Windows packages Download
macOS packages Download
UI artifacts Download
UI macOS artifacts Download

GHCR images (amd64)

This comment is updated by the Release workflow. Artifact links expire according to the workflow retention policy.

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.

2 participants