libp2p / libp2p/rust-libp2p

SwarmBuilder::with_websocket hardcodes dns::tokio::Transport::system, bypassing with_dns_config (breaks on Android)

Open
#6,529 0 comments 0 reactions 0 assignees View on GitHub

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.