Skip to content

fix(android): recover default-interface index via Os.if_nametoindex#8889

Draft
garmr-ulfr wants to merge 2 commits into
mainfrom
garmr/fix/android-default-interface-index
Draft

fix(android): recover default-interface index via Os.if_nametoindex#8889
garmr-ulfr wants to merge 2 commits into
mainfrom
garmr/fix/android-default-interface-index

Conversation

@garmr-ulfr

@garmr-ulfr garmr-ulfr commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Problem

On Android, every sing-box outbound (direct, the auto-selector, and proxy outbounds) and DNS failed with no available network interface, while the UI still reported the VPN as Connected. Observed on Android 10 / API 29 (Samsung SM-G960U1); the condition persisted for the whole session with zero successful connections, and the auto-selector churned through servers marking each hard_demoted — a consequence, not the cause.

Root cause

DefaultNetworkMonitor.checkDefaultInterfaceUpdate is the only path that delivers the default network interface to sing-box (via updateDefaultInterface). It resolved the interface index solely through NetworkInterface.getByName(name).index, which relies on the interface-enumeration syscall. That syscall is restricted on some Android versions/ROMs, where getByName returns null or throws. On failure the 10-retry loop exhausted and returned without ever calling updateDefaultInterface, leaving sing-box with no default interface — so every outbound failed to bind.

The sibling PlatformInterfaceWrapper.getInterfaces() was already hardened for this exact case with an Os.if_nametoindex fallback; checkDefaultInterfaceUpdate was not.

Fix

Fall back to Os.if_nametoindex(interfaceName) when getByName cannot resolve the index, mirroring the hardened sibling, and retry only when the index is still unresolvable (<= 0). Also early-return on a null interface name instead of burning the retry budget on getByName(null).

Testing

Needs a build + on-device check on an API 29 device to confirm.

NetworkInterface.getByName relies on the interface-enumeration syscall,
which is restricted on some Android versions/ROMs (returns null or throws
there). When it failed, checkDefaultInterfaceUpdate exhausted its retries
without ever calling updateDefaultInterface, so sing-box never received a
default interface and every outbound failed with "no available network
interface".

Fall back to Os.if_nametoindex when getByName cannot resolve the index,
mirroring the already-hardened getInterfaces sibling, and retry only when
the index is still unresolvable. Also early-return on a null interface
name instead of burning the retry budget on getByName(null).
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3030eea9-84dc-40ba-912d-48f0ec862610

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch garmr/fix/android-default-interface-index

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

Copilot AI 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.

Pull request overview

This PR addresses an Android-specific failure mode where sing-box never receives a default network interface index, causing all outbounds/DNS to fail with “no available network interface” even while the VPN appears connected. It hardens DefaultNetworkMonitor.checkDefaultInterfaceUpdate to recover the interface index on restricted Android ROMs by falling back to Os.if_nametoindex.

Changes:

  • Add Os.if_nametoindex(interfaceName) fallback when NetworkInterface.getByName cannot resolve an interface index.
  • Avoid retrying when the interface name is null by early-returning before entering the retry loop.
  • Retry only when the resolved index is still not usable (<= 0).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
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