rust-libp2p icon indicating copy to clipboard operation
rust-libp2p copied to clipboard

Support `/dnsaddr` in web environments (wasm-bindgen)

Open oblique opened this issue 1 year ago • 9 comments

Description

Enable DNS lookup for web environments (wasm-bindgen). This can be achieved with DNS over HTTPS.

Motivation

I want to be able to use /dnsaddr in web environments.

Requirements

There are two options to implement this:

  1. libp2p-dns needs to be internally refactored to hide hickory types from WASM. Also we need to decide if we are going to support DoH to native systems as well, or if it will be just for WASM.
  2. Create libp2p-dns-websys. The bad thing about this is to reimplement all the retry logic. The good part about this is that we need to implement support only for /dnsaddr since /dns can be handled well by *-websys transprots.

Examples of querying DoH:

Lookup for IPv4

curl --header 'accept: application/dns-json' 'https://1.1.1.1/dns-query?type=1&name=cloudflare.com'

Lookup for IPv6

curl --header 'accept: application/dns-json' 'https://1.1.1.1/dns-query?type=28&name=cloudflare.com'

Lookup for TXT

curl --header 'accept: application/dns-json' 'https://1.1.1.1/dns-query?type=16&name=cloudflare.com'

Open questions

No response

Are you planning to do it yourself in a pull request ?

Maybe

oblique avatar Aug 05 '24 11:08 oblique

I have attempted this myself a few months ago but couldnt really settle on how I would want but do think we could go with 2, which would keep inline with what we are doing now.

dariusc93 avatar Aug 08 '24 12:08 dariusc93

+1

(I just opened #5619 for this same thing, so I will close that as it's duplicate of this issue)

DougAnderson444 avatar Oct 03 '24 16:10 DougAnderson444

Since

/dns can be handled well by *-websys transprots

should we name this libp2p-dnsaddr-websys instead?

DougAnderson444 avatar Nov 26 '24 14:11 DougAnderson444

@dariusc93 do you already have a branch & pull request on the go for this? I need this too, happy to help work on it.

DougAnderson444 avatar Nov 26 '24 14:11 DougAnderson444

Hi @DougAnderson444 did you implement this? Willing to upstream it? 😁

jxs avatar Jan 27 '25 11:01 jxs

I did do it with a fetch to 1.1.1.1 in a few lines of code but didn't integrate it into libp2p

DougAnderson444 avatar Jan 28 '25 23:01 DougAnderson444

@DougAnderson444 do you mean you resolve the dnsaddr before you give it to libp2p? We also do the same in Lumina. Actually we plan to write a proper integration (i.e. libp2p-dnsaddr-websys) the next 1-2 months if someone doesn't do it.

oblique avatar Jan 29 '25 09:01 oblique

@oblique yes that's exactly it. I didn't have the time to do a proper integration (as per this issue), it was too far down on the TODO list for me personally.

DougAnderson444 avatar Jan 29 '25 12:01 DougAnderson444

I just did this:

#[derive(Debug, serde::Deserialize)]
struct DnsTXTQuery {
    /// 'answer' is 'Answer' in the DNS TXT response json
    #[serde(rename = "Answer")]
    answer: Vec<Answer>,
}

#[derive(Debug, serde::Deserialize)]
struct Answer {
    data: String,
}

pub async fn fetch_dns_query(domain: String) -> Result<Vec<String>, JsValue> {
    let opts = RequestInit::new();
    opts.set_method("GET");
    opts.set_mode(RequestMode::Cors);

    // take /dnsaddr/peerpiper.io and convert to _dnsaddr.peerpiper.io
    let domain = domain.replace("/dnsaddr/", "_dnsaddr.");
    let url = format!("https://1.1.1.1/dns-query?type=16&name={domain}");

    let request = Request::new_with_str_and_init(&url, &opts)?;
    request.headers().set("Accept", "application/dns-json")?;

    let window = web_sys::window().ok_or_else(|| JsValue::from_str("no window"))?;
    let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
    let resp: Response = resp_value.dyn_into()?;
    let json = JsFuture::from(resp.json()?).await?;
    let multiaddrs: DnsTXTQuery = serde_wasm_bindgen::from_value(json)?;

    log::debug!("multiaddrs: {:?}", multiaddrs);

    let multiaddrs: Vec<String> = multiaddrs
        .answer
        .iter()
        .map(|a| a.data.replace("dnsaddr=", "").trim_matches('"').to_string())
        .collect();
    Ok(multiaddrs)
}

DougAnderson444 avatar Apr 07 '25 17:04 DougAnderson444