SwarmBuilder::with_websocket hardcodes dns::tokio::Transport::system, bypassing with_dns_config (breaks on Android)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 5.6k
- Forks
- 1.3k
- Avg merge
- 8h 47m
- Merged PRs (30d)
- 19
Description
## Summary
The tokio flavour of `SwarmBuilder::with_websocket` unconditionally wraps its inner TCP transport in a **system-config** DNS transport:
https://github.com/libp2p/rust-libp2p/blob/93c505994dfb99bf47f44a415d65d4eefa66ab02/libp2p/src/builder/phase/websocket.rs#L118-L127
This ignores any resolver configuration supplied earlier via `with_dns_config`. On targets where the system resolver is unavailable, the websocket phase fails even though the user explicitly configured a custom resolver one phase earlier.
**Concrete case (Android):** hickory-resolver 0.26's `system_conf` reads the system DNS via JNI (`ndk-context`). In host environments that never initialize the ndk context — e.g. React Native / uniffi mobile apps, where no `android-activity`-style glue runs — `read_system_conf()` fails with `android context was not initialized`. Switching the DNS phase to `with_dns_config(custom_cfg, opts)` fixes that call site, but `with_websocket` then constructs a *second*, system-config resolver and fails with the byte-for-byte identical error. That makes it genuinely confusing to debug: it looks exactly like the bug you just fixed.
## Expected behavior
One of:
- `with_websocket` reuses the resolver configuration established in the DNS phase (or skips DNS-wrapping entirely when the outer transport is already DNS-wrapped);
- a variant like `with_websocket_dns_config(cfg, opts, ...)` exists so the resolver can be supplied;
- at minimum, the `with_websocket` docs mention the hidden `Transport::system` call and its platform requirements.
## Actual behavior
`with_websocket` always calls `libp2p_dns::tokio::Transport::system` and returns `WebsocketError(Dns(...))` on Android RN hosts, regardless of `with_dns_config`.
## Workaround
On Android we skip the websocket transport via the `WebsocketPhase::with_relay_client` shortcut (which calls `without_websocket()` internally). Acceptable when websocket has no consumers on that platform, but it forks the builder chain per target and silently removes `/ws`/`/wss` dial capability.
## Version
- master @ 93c5059 (`libp2p/src/builder/phase/websocket.rs:123`)
- also present in libp2p 0.56.0 (same line in the `impl_websocket_builder!` expansion)
- hickory-resolver 0.26.1
## Would you like to work on fixing this bug?
Happy to send a PR once maintainers agree on the preferred direction.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with libp2p/src/builder/phase/websocket.rs around lines 118-127 and trace how the websocket phase constructs its DNS transport after with_dns_config. Compare the available expected approaches and verify the behavior on Android when a custom resolver is configured. Done means websocket setup no longer unconditionally uses the system resolver or breaks the configured DNS path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100