Summary
Desktop-advertised iroh-http nodes are invisible to iOS and Android browsers. The desktop discovery stack (iroh-http-discovery → iroh-mdns-address-lookup → swarm-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:
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.
- Auto-dial parity: implement an iroh
AddressLookup fed by the browse stream so desktop fetch(nodeId) continues to auto-resolve LAN peers (mirror MobileAddressLookup).
- 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)
- 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:
- iOS —
Info.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.
- Android —
AndroidManifest.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
- Desktop advertise is visible to Apple's
dns-sd -B _<svc>._udp local and to iOS NWBrowser (a PTR record is emitted).
node.browse() on iOS and Android discovers a desktop-advertised node on the same LAN and can dial it (fetch(nodeId) auto-resolves).
- No regression to mobile→desktop, desktop↔desktop, or mobile↔mobile discovery.
- Desktop
fetch(nodeId) still auto-resolves LAN peers via an AddressLookup fed by browse.
- 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.
- 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
Summary
Desktop-advertised iroh-http nodes are invisible to iOS and Android browsers. The desktop discovery stack (
iroh-http-discovery→iroh-mdns-address-lookup→ swarm-discovery) does not emit a standard DNS-SDPTRrecord, which is the record Apple's mDNSResponder (NWBrowser,dns-sd) and Android'sNsdManageruse to enumerate service instances. Without a PTR answer, those platforms never register the service, sonode.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-0.6.3/src/sender.rsmake_response()addsSRV+A/AAAA+TXTanswers for{peer_id}._<service>._udp.local, but noPTRfor_<service>._udp.local. Its receiver (receiver.rs) likewise discovers peers by parsingSRVanswers, not PTR.deno task advertise cleantestconfirmed running (nodeuynbudsem…),dns-sd -B _cleantest._udp localreturned zero results. Same for_iroh-http._udp.deno task browse(swarm-discovery) does pick up SRV-bearing advertisers, so mobile→desktop discovery works; only desktop→mobile is broken.{endpoint_id}._<service>._udp.localwith the base32 endpoint id as instance name, matching the iOS_<serviceName>._udpdescriptor. 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.P1because 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-sdcrate (already present in the dependency tree), and wire discovered peers into iroh's dialer via a customAddressLookup— the same "browse events feed an AddressLookup" pattern the mobile side already uses (MobileAddressLookup, #310).Proposed shape:
iroh-http-discovery: replace (or augment) the swarm-discovery-basedstart_advertise/start_browsewith amdns-sd-based implementation that:_<serviceName>._udp.localwith a proper PTR + SRV + TXT (publishpkTXT for symmetry with mobile advertisers, and keep the base32 endpoint id as the instance name).PeerDiscoveryEvents.AddressLookupfed by the browse stream so desktopfetch(nodeId)continues to auto-resolve LAN peers (mirrorMobileAddressLookup).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 fromdocs/features/discovery.md,docs/guidelines/tauri.md, andpackages/iroh-http-tauri/README.md). It must cover, for a consuming Tauri app:Info.ios.plist(merged by Tauri):NSLocalNetworkUsageDescription(triggers the Local Network prompt) andNSBonjourServiceslisting every_<serviceName>._udptype the app browses/advertises; plus linkingSystemConfigurationviabundle.iOS.frameworks. Note the first-browse permission prompt and how to re-enable under Settings → Privacy & Security → Local Network.AndroidManifest.xmlpermissions:INTERNET,ACCESS_NETWORK_STATE,CHANGE_WIFI_MULTICAST_STATE, and for API 33+NEARBY_WIFI_DEVICES(withneverForLocation), or the pre-33ACCESS_FINE_LOCATIONpath."iroh-http"→_iroh-http._udp), and the rule that each customserviceNameneeds its own declared entry on iOS.Acceptance criteria
dns-sd -B _<svc>._udp localand to iOSNWBrowser(a PTR record is emitted).node.browse()on iOS and Android discovers a desktop-advertised node on the same LAN and can dial it (fetch(nodeId)auto-resolves).fetch(nodeId)still auto-resolves LAN peers via anAddressLookupfed by browse.docs/, is linked from the discovery feature doc, the Tauri guidelines, and the plugin README, and documents both iOS and Android requirements.npm run ci.)Relation
pkTXT + PTR).MobileAddressLookup; this brings desktop to the same model).