Skip to content

Standardize desktop mDNS on DNS-SD (PTR+SRV+TXT) so iOS/Android can discover desktop nodes #329

Description

@momics

Summary

Desktop-advertised iroh-http nodes are invisible to iOS and Android browsers. The desktop discovery stack (iroh-http-discoveryiroh-mdns-address-lookupswarm-discovery) does not emit a standard DNS-SD PTR record, which is the record Apple's mDNSResponder (NWBrowser, dns-sd) and Android's NsdManager use to enumerate service instances. Without a PTR answer, those platforms never register the service, so node.browse() on mobile finds nothing when a desktop node advertises.

This is the deeper cause behind the symptom fixed superficially in #318. #318 taught the mobile parsers to derive the node-id from the instance name (a TXT-vs-instance-name mismatch), but that only matters after discovery happens. The records never reach Apple/Android at all, because swarm-discovery speaks a non-standard, PTR-less variant of mDNS optimized for iroh-to-iroh swarms.

Evidence (verified)

  • swarm-discovery omits PTR. swarm-discovery-0.6.3/src/sender.rs make_response() adds SRV + A/AAAA + TXT answers for {peer_id}._<service>._udp.local, but no PTR for _<service>._udp.local. Its receiver (receiver.rs) likewise discovers peers by parsing SRV answers, not PTR.
  • Apple can't see it. With deno task advertise cleantest confirmed running (node uynbudsem…), dns-sd -B _cleantest._udp local returned zero results. Same for _iroh-http._udp.
  • Reverse direction works. deno task browse (swarm-discovery) does pick up SRV-bearing advertisers, so mobile→desktop discovery works; only desktop→mobile is broken.
  • Service type is already aligned: swarm-discovery advertises {endpoint_id}._<service>._udp.local with the base32 endpoint id as instance name, matching the iOS _<serviceName>._udp descriptor. The only missing piece on the wire is the PTR record (and standards-compliant framing).

Impact

Local-network discovery — the entire purpose of node.advertise() / node.browse() — silently fails in the most common cross-device scenario (a phone discovering a laptop/desktop/server on the same Wi-Fi). No error is surfaced; the peer simply never appears. P1 because it breaks a core advertised capability across the desktop↔mobile boundary with no in-band signal that anything is wrong.

Partial workarounds today: mobile→desktop discovery works, and global DNS (Pkarr) discovery works regardless of LAN.

Remediation

Rework desktop discovery to speak standard DNS-SD (emitting PTR+SRV+TXT) using the RFC-compliant mdns-sd crate (already present in the dependency tree), and wire discovered peers into iroh's dialer via a custom AddressLookup — the same "browse events feed an AddressLookup" pattern the mobile side already uses (MobileAddressLookup, #310).

Proposed shape:

  1. iroh-http-discovery: replace (or augment) the swarm-discovery-based start_advertise/start_browse with a mdns-sd-based implementation that:
    • advertises _<serviceName>._udp.local with a proper PTR + SRV + TXT (publish pk TXT for symmetry with mobile advertisers, and keep the base32 endpoint id as the instance name).
    • browses via standard DNS-SD and yields the same PeerDiscoveryEvents.
  2. Auto-dial parity: implement an iroh AddressLookup fed by the browse stream so desktop fetch(nodeId) continues to auto-resolve LAN peers (mirror MobileAddressLookup).
  3. Interop targets (all must hold on one LAN):
    • desktop → iOS/Android ✅ (the fix)
    • iOS/Android → desktop ✅ (no regression)
    • desktop ↔ desktop ✅ (no regression)
    • iOS/Android ↔ iOS/Android ✅ (unchanged; native stacks)
  4. Document mobile setup (see below).

Open question to resolve in the PR: fully replace swarm-discovery, or run standard DNS-SD in addition to it. Prefer full replacement for a single, interoperable wire format unless auto-dial integration forces otherwise.

Documentation requirement

Add a dedicated "mDNS / DNS-SD on mobile" setup guide as part of the Tauri docs (new doc under docs/, linked from docs/features/discovery.md, docs/guidelines/tauri.md, and packages/iroh-http-tauri/README.md). It must cover, for a consuming Tauri app:

  • iOSInfo.ios.plist (merged by Tauri): NSLocalNetworkUsageDescription (triggers the Local Network prompt) and NSBonjourServices listing every _<serviceName>._udp type the app browses/advertises; plus linking SystemConfiguration via bundle.iOS.frameworks. Note the first-browse permission prompt and how to re-enable under Settings → Privacy & Security → Local Network.
  • AndroidAndroidManifest.xml permissions: INTERNET, ACCESS_NETWORK_STATE, CHANGE_WIFI_MULTICAST_STATE, and for API 33+ NEARBY_WIFI_DEVICES (with neverForLocation), or the pre-33 ACCESS_FINE_LOCATION path.
  • serviceName ↔ service type mapping ("iroh-http"_iroh-http._udp), and the rule that each custom serviceName needs its own declared entry on iOS.
  • A short desktop↔mobile interop note once the fix lands.

Acceptance criteria

  1. Desktop advertise is visible to Apple's dns-sd -B _<svc>._udp local and to iOS NWBrowser (a PTR record is emitted).
  2. node.browse() on iOS and Android discovers a desktop-advertised node on the same LAN and can dial it (fetch(nodeId) auto-resolves).
  3. No regression to mobile→desktop, desktop↔desktop, or mobile↔mobile discovery.
  4. Desktop fetch(nodeId) still auto-resolves LAN peers via an AddressLookup fed by browse.
  5. A mobile mDNS setup doc exists under docs/, is linked from the discovery feature doc, the Tauri guidelines, and the plugin README, and documents both iOS and Android requirements.
  6. Manual cross-device repro (desktop advertise → iOS discover, and desktop advertise → Android discover) documented in the PR. (Mobile native code is not covered by npm run ci.)

Relation

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High prioritybugSomething isn't workingconnectivityPeer discovery and connectiondxDeveloper experience

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions