Support `/dnsaddr` in web environments (wasm-bindgen)
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:
libp2p-dnsneeds to be internally refactored to hidehickorytypes 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.- 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/dnsaddrsince/dnscan 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
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.
+1
(I just opened #5619 for this same thing, so I will close that as it's duplicate of this issue)
Since
/dns can be handled well by *-websys transprots
should we name this libp2p-dnsaddr-websys instead?
@dariusc93 do you already have a branch & pull request on the go for this? I need this too, happy to help work on it.
Hi @DougAnderson444 did you implement this? Willing to upstream it? 😁
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 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 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.
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)
}