Android: enable LAN mDNS discovery via NsdManager (netlink RTM_GETLINK blocked on API >= 30) #1
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
LAN peer discovery via mDNS is disabled on Android. The Android-native replacement is
NsdManager(Network Service Discovery), wired into iroh through a customAddressLookupimpl. Connectivity is unaffected — relays + DNS/Pkarr discovery cover peer reachability — but same-LAN Android peers cannot discover each other's direct address without a relay hop until this lands.Root cause
iroh's mDNS backend (
iroh-mdns-address-lookup→swarm-discovery) enumerates network interfaces via the netlinkRTM_GETLINKdump. Android deniesRTM_GETLINKfor any app targeting API ≥ 30 — it requires thenlmsg_readprivSELinux capability that theuntrusted_appdomain does not have (Androidb/155595000). Our app targets API 36, so the mDNS service fails to initialize, and because the failure propagates out ofEndpoint::bind(), the core never starts and the app hangs on the loading screen.Observed on a Pixel 9a (debug build), logcat:
This is not a missing manifest permission.
CHANGE_WIFI_MULTICAST_STATE(which we already hold, for the multicast lock) governs receiving inbound multicast — not interface enumeration. There is no app-grantable permission for the netlink path; Google removed it deliberately in Android 11. Same wall is hit by Syncthing, libtorrent, Go'snet, Qt, and IPFS.Current workaround (shipped)
crates/hopchat-core/src/lib.rs— theMdnsAddressLookupis#[cfg(not(target_os = "android"))]-gated out of the endpoint builder. Android binds withpresets::N0(relays + DNS/Pkarr) only. Desktop/iOS behaviour is unchanged.Proposed fix: NsdManager-backed
AddressLookupiroh takes a pluggable
iroh::address_lookup::AddressLookuptrait (we already passMemoryLookupand, off-Android,MdnsAddressLookup). Implement aNsdAddressLookupfor Android:NsdManagerwrapper —registerServiceto advertise this endpoint,discoverServices+resolveServiceto find peers. Encode the irohEndpointIdin the service name / TXT record (mirror swarm-discovery's encoding). Watch out for: serialized resolve pre-API 34 (queue resolves), name collisions, teardown on pause, and known NsdManager flakiness below Android 13.network/multicast.rs); the new direction is Kotlin→Rust callbacks delivering discovered(EndpointId, SocketAddr)entries (global JNI ref or channel).AddressLookupimpl — feed resolved peer addresses into iroh, keyed byEndpointId, modelled onMemoryLookup.First thing to nail down: the exact method surface of
AddressLookup(push vs pull, async shape), since it dictates how the Kotlin callbacks plug in.Estimated complexity: medium — a few focused days. Bounded by the existing trait seam + JNI precedent; no upstream iroh solution exists (the iroh community discusses mDNS generally but not an Android/NsdManager path), so this would be net-new.
References