Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dns): initial support dns module #825

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ Everything else inherited from [Uint8Array](https://developer.mozilla.org/en-US/

[subtle.verify](https://nodejs.org/api/webcrypto.html#subtleverifyalgorithm-key-signature-datah)

## dns

[lookup](https://nodejs.org/api/dns.html#dnslookuphostname-options-callback)

## events

[EventEmitter](https://nodejs.org/api/events.html#class-eventemitter)
Expand Down
27 changes: 27 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ The test runner also has support for filters. Using filters is as simple as addi
| child_process | ✔︎ | ✔︎⏱ |
| console | ✔︎ | ✔︎ |
| crypto | ✔︎ | ✔︎ |
| dns | ✔︎ | ✔︎ |
| events | ✔︎ | ✔︎ |
| fs/promises | ✔︎ | ✔︎ |
| fs | ✔︎ | ✘⏱ |
Expand Down
1 change: 1 addition & 0 deletions build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const ES_BUILD_OPTIONS = {
"console",
"node:console",
"crypto",
"dns",
"os",
"fs",
"child_process",
Expand Down
29 changes: 29 additions & 0 deletions libs/llrt_dns_cache/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
name = "llrt_dns_cache"
description = "LLRT dns cache helpers"
version = "0.5.1-beta"
edition = "2021"
license = "Apache-2.0"
repository = "https://github.com/awslabs/llrt"
readme = "README.md"

[lib]
name = "llrt_dns_cache"
path = "src/lib.rs"

[dependencies]
hyper = { version = "1", features = ["client"] }
hyper-rustls = { version = "0.27", default-features = false, features = [
"webpki-roots",
"webpki-tokio",
"ring",
] }
hyper-util = "0.1"
llrt_context = { version = "0.5.1-beta", path = "../../libs/llrt_context" }
llrt_utils = { version = "0.5.1-beta", path = "../../libs/llrt_utils", default-features = false }
rquickjs = { git = "https://github.com/DelSkayn/rquickjs.git", version = "0.9.0", features = [
"macro",
], default-features = false }
tokio = "1"
tower-service = "0.3.3"
quick_cache = "0.6.9"
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
use std::future::Future;
use std::net::SocketAddr;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{self, Poll};
use std::time::{Duration, Instant};
use std::{io, vec};

use hyper_util::client::legacy::connect::dns::Name;
use hyper_util::client::legacy::connect::HttpConnector;
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use std::{
future::Future,
io,
net::{SocketAddr, SocketAddrV4, SocketAddrV6},
pin::Pin,
result::Result as StdResult,
str::FromStr,
sync::Arc,
task::{self, Poll},
time::{Duration, Instant},
vec,
};

use hyper_util::client::legacy::connect::{dns::Name, HttpConnector};
use llrt_utils::object::ObjectExt;
use quick_cache::sync::Cache;
use std::io::Result;
use rquickjs::Value;
use tokio::sync::Semaphore;
use tower_service::Service;

Expand Down Expand Up @@ -56,9 +63,9 @@ pub struct CachedDnsResolver {
impl Service<Name> for CachedDnsResolver {
type Response = SocketAddrs;
type Error = io::Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response>> + Send>>;
type Future = Pin<Box<dyn Future<Output = std::io::Result<Self::Response>> + Send>>;

fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<Result<()>> {
fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<std::io::Result<()>> {
Poll::Ready(Ok(()))
}

Expand Down Expand Up @@ -136,3 +143,52 @@ impl CachedDnsResolver {
HttpConnector::<Self>::new_with_resolver(self)
}
}

pub async fn lookup_host(
hostname: &str,
options: Option<Value<'_>>,
) -> StdResult<(String, i32), std::io::Error> {
let mut family = 0;
if let Some(options) = options {
family = if let Some(v) = options.as_int() {
if !matches!(v, 4 | 6) {
return Err(io::Error::new::<String>(
io::ErrorKind::InvalidInput,
"If options is an integer, then it must be 4 or 6".into(),
));
}
v
} else if let Ok(Some(v)) = options.get_optional::<_, i32>("family") {
if !matches!(v, 4 | 6 | 0) {
return Err(io::Error::new::<String>(
io::ErrorKind::InvalidInput,
"If family record is exist, then it must be 4, 6, or 0".into(),
));
}
v
} else {
0
}
}

let addrs = tokio::net::lookup_host((hostname, 0)).await?;
let addrs = addrs.collect::<Vec<_>>();

for ip in addrs {
if matches!(family, 4 | 0) {
if let Ok(ipv4) = SocketAddrV4::from_str(&ip.to_string()) {
return Ok((ipv4.ip().to_string(), 4));
}
}
if matches!(family, 6 | 0) {
if let Ok(ipv6) = SocketAddrV6::from_str(&ip.to_string()) {
return Ok((ipv6.ip().to_string(), 6));
}
}
}

Err(io::Error::new::<String>(
io::ErrorKind::NotFound,
"No values ware found matching the criteria".into(),
))
}
2 changes: 2 additions & 0 deletions llrt_core/src/module_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::modules::{
child_process::ChildProcessModule,
console::ConsoleModule,
crypto::CryptoModule,
dns::DnsModule,
events::EventsModule,
fs::{FsModule, FsPromisesModule},
llrt::{hex::LlrtHexModule, uuid::LlrtUuidModule, xml::LlrtXmlModule},
Expand Down Expand Up @@ -107,6 +108,7 @@ impl Default for ModuleBuilder {
.with_global(crate::modules::perf_hooks::init)
.with_module(ZlibModule)
.with_module(TtyModule)
.with_module(DnsModule)
}
}

Expand Down
4 changes: 2 additions & 2 deletions llrt_core/src/modules/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
pub use llrt_modules::{
abort, assert, buffer, child_process, crypto, events, exceptions, fs, http, navigator, net, os,
path, perf_hooks, process, stream_web, tty, url, zlib,
abort, assert, buffer, child_process, crypto, dns, events, exceptions, fs, http, navigator,
net, os, path, perf_hooks, process, stream_web, tty, url, zlib,
};

pub mod console;
Expand Down
3 changes: 3 additions & 0 deletions llrt_modules/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ all = [
"buffer",
"child-process",
"crypto",
"dns",
"events",
"exceptions",
"fs",
Expand All @@ -38,6 +39,7 @@ assert = ["llrt_assert"]
buffer = ["llrt_buffer"]
child-process = ["llrt_child_process"]
crypto = ["llrt_crypto"]
dns = ["llrt_dns"]
events = ["llrt_events"]
exceptions = ["llrt_exceptions"]
fs = ["llrt_fs"]
Expand All @@ -60,6 +62,7 @@ llrt_assert = { version = "0.5.1-beta", path = "../modules/llrt_assert", optiona
llrt_buffer = { version = "0.5.1-beta", path = "../modules/llrt_buffer", optional = true }
llrt_child_process = { version = "0.5.1-beta", path = "../modules/llrt_child_process", optional = true }
llrt_crypto = { version = "0.5.1-beta", path = "../modules/llrt_crypto", optional = true }
llrt_dns = { version = "0.5.1-beta", path = "../modules/llrt_dns", optional = true }
llrt_events = { version = "0.5.1-beta", path = "../modules/llrt_events", optional = true }
llrt_exceptions = { version = "0.5.1-beta", path = "../modules/llrt_exceptions", optional = true }
llrt_fs = { version = "0.5.1-beta", path = "../modules/llrt_fs", optional = true }
Expand Down
1 change: 1 addition & 0 deletions llrt_modules/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ async fn main() -> anyhow::Result<()> {
| buffer | ✔︎ | ✔︎️ | `buffer` | `llrt_buffer` |
| child process | ✔︎ | ⚠️ | `child-process` | `llrt_child_process` |
| crypto | ✔︎ | ⚠️ | `crypto` | `llrt_cryto` |
| dns | ✔︎ | ⚠️ | `dns` | `llrt_dns` |
| events | ✔︎ | ⚠️ | `events` | `llrt_events` |
| exceptions | ✔︎ | ⚠️ | `exceptions` | `llrt_exceptions` |
| fs/promises | ✔︎ | ⚠️ | `fs` | `llrt_fs` |
Expand Down
2 changes: 2 additions & 0 deletions llrt_modules/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ mod modules {
pub use llrt_child_process as child_process;
#[cfg(feature = "crypto")]
pub use llrt_crypto as crypto;
#[cfg(feature = "dns")]
pub use llrt_dns as dns;
#[cfg(feature = "events")]
pub use llrt_events as events;
#[cfg(feature = "exceptions")]
Expand Down
20 changes: 20 additions & 0 deletions modules/llrt_dns/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "llrt_dns"
description = "LLRT Module dns"
version = "0.5.1-beta"
edition = "2021"
license = "Apache-2.0"
repository = "https://github.com/awslabs/llrt"
readme = "README.md"

[lib]
name = "llrt_dns"
path = "src/lib.rs"

[dependencies]
llrt_context = { version = "0.5.1-beta", path = "../../libs/llrt_context" }
llrt_dns_cache = { version = "0.5.1-beta", path = "../../libs/llrt_dns_cache" }
llrt_utils = { version = "0.5.1-beta", path = "../../libs/llrt_utils", default-features = false }
rquickjs = { git = "https://github.com/DelSkayn/rquickjs.git", version = "0.9.0", features = [
"macro",
], default-features = false }
64 changes: 64 additions & 0 deletions modules/llrt_dns/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use llrt_context::CtxExtension;
use llrt_dns_cache::lookup_host;
use llrt_utils::{
module::{export_default, ModuleInfo},
result::ResultExt,
};
use rquickjs::{
module::{Declarations, Exports, ModuleDef},
prelude::{Func, Rest},
Ctx, Error, Exception, Function, IntoJs, Null, Result, Value,
};

fn lookup<'js>(ctx: Ctx<'js>, hostname: String, args: Rest<Value<'js>>) -> Result<()> {
let mut args_iter = args.0.into_iter().rev();
let cb: Function = args_iter
.next()
.and_then(|v| v.into_function())
.or_throw_msg(&ctx, "Callback parameter is not a function")?;

ctx.clone().spawn_exit(async move {
match lookup_host(&hostname, args_iter.next()).await {
Ok((address, family)) => {
() = cb.call((Null.into_js(&ctx), address, family))?;
Ok::<_, Error>(())
},
Err(err) => {
() = cb.call((Exception::from_message(ctx, &err.to_string()),))?;
Ok(())
},
}
})?;
Ok(())
}

pub struct DnsModule;

impl ModuleDef for DnsModule {
fn declare(declare: &Declarations) -> Result<()> {
declare.declare("lookup")?;

declare.declare("default")?;
Ok(())
}

fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {
export_default(ctx, exports, |default| {
default.set("lookup", Func::from(lookup))?;
Ok(())
})?;

Ok(())
}
}

impl From<DnsModule> for ModuleInfo<DnsModule> {
fn from(val: DnsModule) -> Self {
ModuleInfo {
name: "dns",
module: val,
}
}
}
1 change: 1 addition & 0 deletions modules/llrt_http/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ itoa = "1"
llrt_abort = { version = "0.5.1-beta", path = "../llrt_abort" }
llrt_compression = { version = "0.5.1-beta", path = "../../libs/llrt_compression", default-features = false }
llrt_context = { version = "0.5.1-beta", path = "../../libs/llrt_context" }
llrt_dns_cache = { version = "0.5.1-beta", path = "../../libs/llrt_dns_cache" }
llrt_encoding = { version = "0.5.1-beta", path = "../../libs/llrt_encoding" }
llrt_json = { version = "0.5.1-beta", path = "../../libs/llrt_json" }
llrt_url = { version = "0.5.1-beta", path = "../llrt_url" }
Expand Down
Loading
Loading