mirror of
https://github.com/denoland/deno.git
synced 2024-11-25 15:29:32 -05:00
feat(unstable): add Deno.resolveDns API (#8790)
This commit is contained in:
parent
cf3202644d
commit
0ef8c915c0
12 changed files with 982 additions and 9 deletions
213
Cargo.lock
generated
213
Cargo.lock
generated
|
@ -397,6 +397,12 @@ dependencies = [
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "data-encoding"
|
||||||
|
version = "2.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "993a608597367c6377b258c25d7120740f00ed23a2252b729b1932dd7866f908"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deno"
|
name = "deno"
|
||||||
version = "1.6.3"
|
version = "1.6.3"
|
||||||
|
@ -449,6 +455,8 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
"tower-test",
|
"tower-test",
|
||||||
|
"trust-dns-client",
|
||||||
|
"trust-dns-server",
|
||||||
"uuid",
|
"uuid",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
|
@ -564,6 +572,8 @@ dependencies = [
|
||||||
"test_util",
|
"test_util",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
|
"trust-dns-proto",
|
||||||
|
"trust-dns-resolver",
|
||||||
"uuid",
|
"uuid",
|
||||||
"webpki",
|
"webpki",
|
||||||
"webpki-roots",
|
"webpki-roots",
|
||||||
|
@ -698,6 +708,24 @@ dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "endian-type"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enum-as-inner"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2 1.0.24",
|
||||||
|
"quote 1.0.7",
|
||||||
|
"syn 1.0.56",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "enum_kind"
|
name = "enum_kind"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -1080,6 +1108,17 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hostname"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"match_cfg",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
|
@ -1238,6 +1277,18 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ipconfig"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7"
|
||||||
|
dependencies = [
|
||||||
|
"socket2",
|
||||||
|
"widestring",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
"winreg 0.6.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
|
@ -1306,6 +1357,12 @@ version = "0.2.82"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929"
|
checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linked-hash-map"
|
||||||
|
version = "0.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
|
@ -1325,6 +1382,15 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lru-cache"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
|
||||||
|
dependencies = [
|
||||||
|
"linked-hash-map",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lsp-types"
|
name = "lsp-types"
|
||||||
version = "0.86.0"
|
version = "0.86.0"
|
||||||
|
@ -1373,6 +1439,12 @@ dependencies = [
|
||||||
"syn 1.0.56",
|
"syn 1.0.56",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "match_cfg"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matches"
|
name = "matches"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
|
@ -1490,6 +1562,15 @@ version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nibble_vec"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
|
||||||
|
dependencies = [
|
||||||
|
"smallvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.19.1"
|
version = "0.19.1"
|
||||||
|
@ -1848,6 +1929,12 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-error"
|
||||||
|
version = "1.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "0.6.13"
|
version = "0.6.13"
|
||||||
|
@ -1878,6 +1965,16 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce082a9940a7ace2ad4a8b7d0b1eac6aa378895f18be598230c5f2284ac05426"
|
checksum = "ce082a9940a7ace2ad4a8b7d0b1eac6aa378895f18be598230c5f2284ac05426"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "radix_trie"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd"
|
||||||
|
dependencies = [
|
||||||
|
"endian-type",
|
||||||
|
"nibble_vec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.7.3"
|
version = "0.7.3"
|
||||||
|
@ -2042,7 +2139,17 @@ dependencies = [
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"webpki-roots",
|
"webpki-roots",
|
||||||
"winreg",
|
"winreg 0.7.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "resolv-conf"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00"
|
||||||
|
dependencies = [
|
||||||
|
"hostname",
|
||||||
|
"quick-error",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3030,6 +3137,95 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "trust-dns-client"
|
||||||
|
version = "0.20.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "498e4de74132fb535c0608d0f221a3e64ddf6585717296afb2baf5925b38f31f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"chrono",
|
||||||
|
"data-encoding",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-util",
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"radix_trie",
|
||||||
|
"rand 0.8.1",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"trust-dns-proto",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "trust-dns-proto"
|
||||||
|
version = "0.20.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "98a0381b2864c2978db7f8e17c7b23cca5a3a5f99241076e13002261a8ecbabd"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"data-encoding",
|
||||||
|
"enum-as-inner",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-io",
|
||||||
|
"futures-util",
|
||||||
|
"idna",
|
||||||
|
"ipnet",
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"rand 0.8.1",
|
||||||
|
"serde",
|
||||||
|
"smallvec",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "trust-dns-resolver"
|
||||||
|
version = "0.20.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3072d18c10bd621cb00507d59cfab5517862285c353160366e37fbf4c74856e4"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"futures-util",
|
||||||
|
"ipconfig",
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"lru-cache",
|
||||||
|
"parking_lot",
|
||||||
|
"resolv-conf",
|
||||||
|
"serde",
|
||||||
|
"smallvec",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"trust-dns-proto",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "trust-dns-server"
|
||||||
|
version = "0.20.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9da8b74feb06ae242b03f40f8da3a414e37827118200fcb3d03d8f825cbbff2c"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"bytes",
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"chrono",
|
||||||
|
"enum-as-inner",
|
||||||
|
"env_logger",
|
||||||
|
"futures-executor",
|
||||||
|
"futures-util",
|
||||||
|
"log",
|
||||||
|
"serde",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
"toml",
|
||||||
|
"trust-dns-client",
|
||||||
|
"trust-dns-proto",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "try-lock"
|
name = "try-lock"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
|
@ -3301,6 +3497,12 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "widestring"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
|
@ -3344,6 +3546,15 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winreg"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winreg"
|
name = "winreg"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
|
|
@ -91,6 +91,8 @@ chrono = "0.4.19"
|
||||||
os_pipe = "0.9.2"
|
os_pipe = "0.9.2"
|
||||||
test_util = { path = "../test_util" }
|
test_util = { path = "../test_util" }
|
||||||
tower-test = "0.4.0"
|
tower-test = "0.4.0"
|
||||||
|
trust-dns-server = "0.20.0"
|
||||||
|
trust-dns-client = "0.20.0"
|
||||||
|
|
||||||
[target.'cfg(unix)'.dev-dependencies]
|
[target.'cfg(unix)'.dev-dependencies]
|
||||||
exec = "0.3.1" # Used in test_raw_tty
|
exec = "0.3.1" # Used in test_raw_tty
|
||||||
|
|
86
cli/dts/lib.deno.unstable.d.ts
vendored
86
cli/dts/lib.deno.unstable.d.ts
vendored
|
@ -835,6 +835,92 @@ declare namespace Deno {
|
||||||
mtime: number | Date,
|
mtime: number | Date,
|
||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
|
|
||||||
|
/** The type of the resource record.
|
||||||
|
* Only the listed types are supported currently. */
|
||||||
|
export type RecordType =
|
||||||
|
| "A"
|
||||||
|
| "AAAA"
|
||||||
|
| "ANAME"
|
||||||
|
| "CNAME"
|
||||||
|
| "MX"
|
||||||
|
| "PTR"
|
||||||
|
| "SRV"
|
||||||
|
| "TXT";
|
||||||
|
|
||||||
|
export interface ResolveDnsOptions {
|
||||||
|
/** The name server to be used for lookups.
|
||||||
|
* If not specified, defaults to the system configuration e.g. `/etc/resolv.conf` on Unix. */
|
||||||
|
nameServer?: {
|
||||||
|
/** The IP address of the name server */
|
||||||
|
ipAddr: string;
|
||||||
|
/** The port number the query will be sent to.
|
||||||
|
* If not specified, defaults to 53. */
|
||||||
|
port?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** If `resolveDns` is called with "MX" record type specified, it will return an array of this interface. */
|
||||||
|
export interface MXRecord {
|
||||||
|
preference: number;
|
||||||
|
exchange: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** If `resolveDns` is called with "SRV" record type specified, it will return an array of this interface. */
|
||||||
|
export interface SRVRecord {
|
||||||
|
priority: number;
|
||||||
|
weight: number;
|
||||||
|
port: number;
|
||||||
|
target: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveDns(
|
||||||
|
query: string,
|
||||||
|
recordType: "A" | "AAAA" | "ANAME" | "CNAME" | "PTR",
|
||||||
|
options?: ResolveDnsOptions,
|
||||||
|
): Promise<string[]>;
|
||||||
|
|
||||||
|
export function resolveDns(
|
||||||
|
query: string,
|
||||||
|
recordType: "MX",
|
||||||
|
options?: ResolveDnsOptions,
|
||||||
|
): Promise<MXRecord[]>;
|
||||||
|
|
||||||
|
export function resolveDns(
|
||||||
|
query: string,
|
||||||
|
recordType: "SRV",
|
||||||
|
options?: ResolveDnsOptions,
|
||||||
|
): Promise<SRVRecord[]>;
|
||||||
|
|
||||||
|
export function resolveDns(
|
||||||
|
query: string,
|
||||||
|
recordType: "TXT",
|
||||||
|
options?: ResolveDnsOptions,
|
||||||
|
): Promise<string[][]>;
|
||||||
|
|
||||||
|
/** ** UNSTABLE**: new API, yet to be vetted.
|
||||||
|
*
|
||||||
|
* Performs DNS resolution against the given query, returning resolved records.
|
||||||
|
* Fails in the cases such as:
|
||||||
|
* - the query is in invalid format
|
||||||
|
* - the options have an invalid parameter, e.g. `nameServer.port` is beyond the range of 16-bit unsigned integer
|
||||||
|
* - timed out
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* const a = await Deno.resolveDns("example.com", "A");
|
||||||
|
*
|
||||||
|
* const aaaa = await Deno.resolveDns("example.com", "AAAA", {
|
||||||
|
* nameServer: { ipAddr: "8.8.8.8", port: 1234 },
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Requires `allow-net` permission.
|
||||||
|
*/
|
||||||
|
export function resolveDns(
|
||||||
|
query: string,
|
||||||
|
recordType: RecordType,
|
||||||
|
options?: ResolveDnsOptions,
|
||||||
|
): Promise<string[] | MXRecord[] | SRVRecord[] | string[][]>;
|
||||||
|
|
||||||
/** **UNSTABLE**: new API, yet to be vetted.
|
/** **UNSTABLE**: new API, yet to be vetted.
|
||||||
*
|
*
|
||||||
* A generic transport listener for message-oriented protocols. */
|
* A generic transport listener for message-oriented protocols. */
|
||||||
|
|
|
@ -5367,3 +5367,279 @@ fn web_platform_tests() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
|
async fn test_resolve_dns() {
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
use std::net::Ipv6Addr;
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::RwLock;
|
||||||
|
use std::time::Duration;
|
||||||
|
use tokio::net::TcpListener;
|
||||||
|
use tokio::net::UdpSocket;
|
||||||
|
use tokio::sync::oneshot;
|
||||||
|
use trust_dns_client::rr::LowerName;
|
||||||
|
use trust_dns_client::rr::RecordType;
|
||||||
|
use trust_dns_client::rr::RrKey;
|
||||||
|
use trust_dns_server::authority::Catalog;
|
||||||
|
use trust_dns_server::authority::ZoneType;
|
||||||
|
use trust_dns_server::proto::rr::rdata::mx::MX;
|
||||||
|
use trust_dns_server::proto::rr::rdata::soa::SOA;
|
||||||
|
use trust_dns_server::proto::rr::rdata::srv::SRV;
|
||||||
|
use trust_dns_server::proto::rr::rdata::txt::TXT;
|
||||||
|
use trust_dns_server::proto::rr::record_data::RData;
|
||||||
|
use trust_dns_server::proto::rr::resource::Record;
|
||||||
|
use trust_dns_server::proto::rr::Name;
|
||||||
|
use trust_dns_server::proto::rr::RecordSet;
|
||||||
|
use trust_dns_server::store::in_memory::InMemoryAuthority;
|
||||||
|
use trust_dns_server::ServerFuture;
|
||||||
|
|
||||||
|
const DNS_PORT: u16 = 4553;
|
||||||
|
|
||||||
|
// Setup DNS server for testing
|
||||||
|
async fn run_dns_server(tx: oneshot::Sender<()>) {
|
||||||
|
let catalog = {
|
||||||
|
let records = {
|
||||||
|
let mut map = BTreeMap::new();
|
||||||
|
let lookup_name = "www.example.com".parse::<Name>().unwrap();
|
||||||
|
let lookup_name_lower = LowerName::new(&lookup_name);
|
||||||
|
|
||||||
|
// Inserts SOA record
|
||||||
|
let soa = SOA::new(
|
||||||
|
Name::from_str("net").unwrap(),
|
||||||
|
Name::from_str("example").unwrap(),
|
||||||
|
0,
|
||||||
|
i32::MAX,
|
||||||
|
i32::MAX,
|
||||||
|
i32::MAX,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
let rdata = RData::SOA(soa);
|
||||||
|
let record = Record::from_rdata(Name::new(), u32::MAX, rdata);
|
||||||
|
let record_set = RecordSet::from(record);
|
||||||
|
map
|
||||||
|
.insert(RrKey::new(Name::root().into(), RecordType::SOA), record_set);
|
||||||
|
|
||||||
|
// Inserts A record
|
||||||
|
let rdata = RData::A(Ipv4Addr::new(1, 2, 3, 4));
|
||||||
|
let record = Record::from_rdata(lookup_name.clone(), u32::MAX, rdata);
|
||||||
|
let record_set = RecordSet::from(record);
|
||||||
|
map.insert(
|
||||||
|
RrKey::new(lookup_name_lower.clone(), RecordType::A),
|
||||||
|
record_set,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Inserts AAAA record
|
||||||
|
let rdata = RData::AAAA(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8));
|
||||||
|
let record = Record::from_rdata(lookup_name.clone(), u32::MAX, rdata);
|
||||||
|
let record_set = RecordSet::from(record);
|
||||||
|
map.insert(
|
||||||
|
RrKey::new(lookup_name_lower.clone(), RecordType::AAAA),
|
||||||
|
record_set,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Inserts ANAME record
|
||||||
|
let rdata = RData::ANAME(Name::from_str("aname.com").unwrap());
|
||||||
|
let record = Record::from_rdata(lookup_name.clone(), u32::MAX, rdata);
|
||||||
|
let record_set = RecordSet::from(record);
|
||||||
|
map.insert(
|
||||||
|
RrKey::new(lookup_name_lower.clone(), RecordType::ANAME),
|
||||||
|
record_set,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Inserts CNAME record
|
||||||
|
let rdata = RData::CNAME(Name::from_str("cname.com").unwrap());
|
||||||
|
let record =
|
||||||
|
Record::from_rdata(Name::from_str("foo").unwrap(), u32::MAX, rdata);
|
||||||
|
let record_set = RecordSet::from(record);
|
||||||
|
map.insert(
|
||||||
|
RrKey::new(lookup_name_lower.clone(), RecordType::CNAME),
|
||||||
|
record_set,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Inserts MX record
|
||||||
|
let rdata = RData::MX(MX::new(0, Name::from_str("mx.com").unwrap()));
|
||||||
|
let record = Record::from_rdata(lookup_name.clone(), u32::MAX, rdata);
|
||||||
|
let record_set = RecordSet::from(record);
|
||||||
|
map.insert(
|
||||||
|
RrKey::new(lookup_name_lower.clone(), RecordType::MX),
|
||||||
|
record_set,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Inserts PTR record
|
||||||
|
let rdata = RData::PTR(Name::from_str("ptr.com").unwrap());
|
||||||
|
let record = Record::from_rdata(
|
||||||
|
Name::from_str("5.6.7.8").unwrap(),
|
||||||
|
u32::MAX,
|
||||||
|
rdata,
|
||||||
|
);
|
||||||
|
let record_set = RecordSet::from(record);
|
||||||
|
map.insert(
|
||||||
|
RrKey::new("5.6.7.8".parse().unwrap(), RecordType::PTR),
|
||||||
|
record_set,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Inserts SRV record
|
||||||
|
let rdata = RData::SRV(SRV::new(
|
||||||
|
0,
|
||||||
|
100,
|
||||||
|
1234,
|
||||||
|
Name::from_str("srv.com").unwrap(),
|
||||||
|
));
|
||||||
|
let record = Record::from_rdata(
|
||||||
|
Name::from_str("_Service._TCP.example.com").unwrap(),
|
||||||
|
u32::MAX,
|
||||||
|
rdata,
|
||||||
|
);
|
||||||
|
let record_set = RecordSet::from(record);
|
||||||
|
map.insert(
|
||||||
|
RrKey::new(lookup_name_lower.clone(), RecordType::SRV),
|
||||||
|
record_set,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Inserts TXT record
|
||||||
|
let rdata =
|
||||||
|
RData::TXT(TXT::new(vec!["foo".to_string(), "bar".to_string()]));
|
||||||
|
let record = Record::from_rdata(lookup_name, u32::MAX, rdata);
|
||||||
|
let record_set = RecordSet::from(record);
|
||||||
|
map.insert(RrKey::new(lookup_name_lower, RecordType::TXT), record_set);
|
||||||
|
|
||||||
|
map
|
||||||
|
};
|
||||||
|
|
||||||
|
let authority = Box::new(Arc::new(RwLock::new(
|
||||||
|
InMemoryAuthority::new(
|
||||||
|
Name::from_str("com").unwrap(),
|
||||||
|
records,
|
||||||
|
ZoneType::Primary,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
)));
|
||||||
|
let mut c = Catalog::new();
|
||||||
|
c.upsert(Name::root().into(), authority);
|
||||||
|
c
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut server_fut = ServerFuture::new(catalog);
|
||||||
|
let socket_addr = SocketAddr::from(([127, 0, 0, 1], DNS_PORT));
|
||||||
|
let tcp_listener = TcpListener::bind(socket_addr).await.unwrap();
|
||||||
|
let udp_socket = UdpSocket::bind(socket_addr).await.unwrap();
|
||||||
|
server_fut.register_socket(udp_socket);
|
||||||
|
server_fut.register_listener(tcp_listener, Duration::from_secs(2));
|
||||||
|
|
||||||
|
// Notifies that the DNS server is ready
|
||||||
|
tx.send(()).unwrap();
|
||||||
|
|
||||||
|
server_fut.block_until_done().await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let (ready_tx, ready_rx) = oneshot::channel();
|
||||||
|
let dns_server_fut = run_dns_server(ready_tx);
|
||||||
|
let handle = tokio::spawn(dns_server_fut);
|
||||||
|
|
||||||
|
// Waits for the DNS server to be ready
|
||||||
|
ready_rx.await.unwrap();
|
||||||
|
|
||||||
|
// Pass: `--allow-net`
|
||||||
|
{
|
||||||
|
let output = util::deno_cmd()
|
||||||
|
.current_dir(util::tests_path())
|
||||||
|
.env("NO_COLOR", "1")
|
||||||
|
.arg("run")
|
||||||
|
.arg("--allow-net")
|
||||||
|
.arg("--unstable")
|
||||||
|
.arg("resolve_dns.ts")
|
||||||
|
.stdout(std::process::Stdio::piped())
|
||||||
|
.stderr(std::process::Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.unwrap()
|
||||||
|
.wait_with_output()
|
||||||
|
.unwrap();
|
||||||
|
let err = String::from_utf8_lossy(&output.stderr);
|
||||||
|
let out = String::from_utf8_lossy(&output.stdout);
|
||||||
|
assert!(output.status.success());
|
||||||
|
assert!(err.starts_with("Check file"));
|
||||||
|
|
||||||
|
let expected =
|
||||||
|
std::fs::read_to_string(util::tests_path().join("resolve_dns.ts.out"))
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(expected, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass: `--allow-net=127.0.0.1:4553`
|
||||||
|
{
|
||||||
|
let output = util::deno_cmd()
|
||||||
|
.current_dir(util::tests_path())
|
||||||
|
.env("NO_COLOR", "1")
|
||||||
|
.arg("run")
|
||||||
|
.arg("--allow-net=127.0.0.1:4553")
|
||||||
|
.arg("--unstable")
|
||||||
|
.arg("resolve_dns.ts")
|
||||||
|
.stdout(std::process::Stdio::piped())
|
||||||
|
.stderr(std::process::Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.unwrap()
|
||||||
|
.wait_with_output()
|
||||||
|
.unwrap();
|
||||||
|
let err = String::from_utf8_lossy(&output.stderr);
|
||||||
|
let out = String::from_utf8_lossy(&output.stdout);
|
||||||
|
assert!(output.status.success());
|
||||||
|
assert!(err.starts_with("Check file"));
|
||||||
|
|
||||||
|
let expected =
|
||||||
|
std::fs::read_to_string(util::tests_path().join("resolve_dns.ts.out"))
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(expected, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Permission error: `--allow-net=deno.land`
|
||||||
|
{
|
||||||
|
let output = util::deno_cmd()
|
||||||
|
.current_dir(util::tests_path())
|
||||||
|
.env("NO_COLOR", "1")
|
||||||
|
.arg("run")
|
||||||
|
.arg("--allow-net=deno.land")
|
||||||
|
.arg("--unstable")
|
||||||
|
.arg("resolve_dns.ts")
|
||||||
|
.stdout(std::process::Stdio::piped())
|
||||||
|
.stderr(std::process::Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.unwrap()
|
||||||
|
.wait_with_output()
|
||||||
|
.unwrap();
|
||||||
|
let err = String::from_utf8_lossy(&output.stderr);
|
||||||
|
let out = String::from_utf8_lossy(&output.stdout);
|
||||||
|
assert!(!output.status.success());
|
||||||
|
assert!(err.starts_with("Check file"));
|
||||||
|
assert!(err.contains(r#"error: Uncaught (in promise) PermissionDenied: network access to "127.0.0.1:4553""#));
|
||||||
|
assert!(out.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Permission error: no permission specified
|
||||||
|
{
|
||||||
|
let output = util::deno_cmd()
|
||||||
|
.current_dir(util::tests_path())
|
||||||
|
.env("NO_COLOR", "1")
|
||||||
|
.arg("run")
|
||||||
|
.arg("--unstable")
|
||||||
|
.arg("resolve_dns.ts")
|
||||||
|
.stdout(std::process::Stdio::piped())
|
||||||
|
.stderr(std::process::Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.unwrap()
|
||||||
|
.wait_with_output()
|
||||||
|
.unwrap();
|
||||||
|
let err = String::from_utf8_lossy(&output.stderr);
|
||||||
|
let out = String::from_utf8_lossy(&output.stdout);
|
||||||
|
assert!(!output.status.success());
|
||||||
|
assert!(err.starts_with("Check file"));
|
||||||
|
assert!(err.contains(r#"error: Uncaught (in promise) PermissionDenied: network access to "127.0.0.1:4553""#));
|
||||||
|
assert!(out.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
handle.abort();
|
||||||
|
}
|
||||||
|
|
36
cli/tests/resolve_dns.ts
Normal file
36
cli/tests/resolve_dns.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
const nameServer = { nameServer: { ipAddr: "127.0.0.1", port: 4553 } };
|
||||||
|
|
||||||
|
const [a, aaaa, aname, cname, mx, ptr, srv, txt] = await Promise.all([
|
||||||
|
Deno.resolveDns("www.example.com", "A", nameServer),
|
||||||
|
Deno.resolveDns("www.example.com", "AAAA", nameServer),
|
||||||
|
Deno.resolveDns("www.example.com", "ANAME", nameServer),
|
||||||
|
Deno.resolveDns("foo", "CNAME", nameServer),
|
||||||
|
Deno.resolveDns("www.example.com", "MX", nameServer),
|
||||||
|
Deno.resolveDns("5.6.7.8", "PTR", nameServer),
|
||||||
|
Deno.resolveDns("_Service._TCP.example.com", "SRV", nameServer),
|
||||||
|
Deno.resolveDns("www.example.com", "TXT", nameServer),
|
||||||
|
]);
|
||||||
|
|
||||||
|
console.log("A");
|
||||||
|
console.log(JSON.stringify(a));
|
||||||
|
|
||||||
|
console.log("AAAA");
|
||||||
|
console.log(JSON.stringify(aaaa));
|
||||||
|
|
||||||
|
console.log("ANAME");
|
||||||
|
console.log(JSON.stringify(aname));
|
||||||
|
|
||||||
|
console.log("CNAME");
|
||||||
|
console.log(JSON.stringify(cname));
|
||||||
|
|
||||||
|
console.log("MX");
|
||||||
|
console.log(JSON.stringify(mx));
|
||||||
|
|
||||||
|
console.log("PTR");
|
||||||
|
console.log(JSON.stringify(ptr));
|
||||||
|
|
||||||
|
console.log("SRV");
|
||||||
|
console.log(JSON.stringify(srv));
|
||||||
|
|
||||||
|
console.log("TXT");
|
||||||
|
console.log(JSON.stringify(txt));
|
16
cli/tests/resolve_dns.ts.out
Normal file
16
cli/tests/resolve_dns.ts.out
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
A
|
||||||
|
["1.2.3.4"]
|
||||||
|
AAAA
|
||||||
|
["1:2:3:4:5:6:7:8"]
|
||||||
|
ANAME
|
||||||
|
["aname.com."]
|
||||||
|
CNAME
|
||||||
|
["cname.com."]
|
||||||
|
MX
|
||||||
|
[{"preference":0,"exchange":"mx.com."}]
|
||||||
|
PTR
|
||||||
|
["ptr.com."]
|
||||||
|
SRV
|
||||||
|
[{"priority":0,"weight":100,"port":1234,"target":"srv.com."}]
|
||||||
|
TXT
|
||||||
|
[["foo","bar"]]
|
|
@ -61,6 +61,8 @@ tokio-rustls = "0.22.0"
|
||||||
uuid = { version = "0.8.2", features = ["v4"] }
|
uuid = { version = "0.8.2", features = ["v4"] }
|
||||||
webpki = "0.21.4"
|
webpki = "0.21.4"
|
||||||
webpki-roots = "0.21.0"
|
webpki-roots = "0.21.0"
|
||||||
|
trust-dns-proto = "0.20.0"
|
||||||
|
trust-dns-resolver = { version = "0.20.0", features = ["tokio-runtime", "serde-config"] }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
fwdansi = "1.1.0"
|
fwdansi = "1.1.0"
|
||||||
|
|
|
@ -33,6 +33,10 @@
|
||||||
return core.jsonOpAsync("op_datagram_send", args, zeroCopy);
|
return core.jsonOpAsync("op_datagram_send", args, zeroCopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveDns(query, recordType, options) {
|
||||||
|
return core.jsonOpAsync("op_dns_resolve", { query, recordType, options });
|
||||||
|
}
|
||||||
|
|
||||||
class Conn {
|
class Conn {
|
||||||
#rid = 0;
|
#rid = 0;
|
||||||
#remoteAddr = null;
|
#remoteAddr = null;
|
||||||
|
@ -210,5 +214,6 @@
|
||||||
Listener,
|
Listener,
|
||||||
shutdown,
|
shutdown,
|
||||||
Datagram,
|
Datagram,
|
||||||
|
resolveDns,
|
||||||
};
|
};
|
||||||
})(this);
|
})(this);
|
||||||
|
|
|
@ -111,6 +111,7 @@
|
||||||
applySourceMap: __bootstrap.errorStack.opApplySourceMap,
|
applySourceMap: __bootstrap.errorStack.opApplySourceMap,
|
||||||
formatDiagnostics: __bootstrap.errorStack.opFormatDiagnostics,
|
formatDiagnostics: __bootstrap.errorStack.opFormatDiagnostics,
|
||||||
shutdown: __bootstrap.net.shutdown,
|
shutdown: __bootstrap.net.shutdown,
|
||||||
|
resolveDns: __bootstrap.net.resolveDns,
|
||||||
listen: __bootstrap.netUnstable.listen,
|
listen: __bootstrap.netUnstable.listen,
|
||||||
connect: __bootstrap.netUnstable.connect,
|
connect: __bootstrap.netUnstable.connect,
|
||||||
listenDatagram: __bootstrap.netUnstable.listenDatagram,
|
listenDatagram: __bootstrap.netUnstable.listenDatagram,
|
||||||
|
|
|
@ -22,6 +22,7 @@ use deno_core::RcRef;
|
||||||
use deno_core::Resource;
|
use deno_core::Resource;
|
||||||
use deno_core::ZeroCopyBuf;
|
use deno_core::ZeroCopyBuf;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
@ -30,6 +31,13 @@ use tokio::io::AsyncWriteExt;
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio::net::UdpSocket;
|
use tokio::net::UdpSocket;
|
||||||
|
use trust_dns_proto::rr::record_data::RData;
|
||||||
|
use trust_dns_proto::rr::record_type::RecordType;
|
||||||
|
use trust_dns_resolver::config::NameServerConfigGroup;
|
||||||
|
use trust_dns_resolver::config::ResolverConfig;
|
||||||
|
use trust_dns_resolver::config::ResolverOpts;
|
||||||
|
use trust_dns_resolver::system_conf;
|
||||||
|
use trust_dns_resolver::AsyncResolver;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use super::net_unix;
|
use super::net_unix;
|
||||||
|
@ -45,6 +53,7 @@ pub fn init(rt: &mut deno_core::JsRuntime) {
|
||||||
super::reg_json_sync(rt, "op_listen", op_listen);
|
super::reg_json_sync(rt, "op_listen", op_listen);
|
||||||
super::reg_json_async(rt, "op_datagram_receive", op_datagram_receive);
|
super::reg_json_async(rt, "op_datagram_receive", op_datagram_receive);
|
||||||
super::reg_json_async(rt, "op_datagram_send", op_datagram_send);
|
super::reg_json_async(rt, "op_datagram_send", op_datagram_send);
|
||||||
|
super::reg_json_async(rt, "op_dns_resolve", op_dns_resolve);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -531,3 +540,249 @@ fn op_listen(
|
||||||
_ => Err(type_error("Wrong argument format!")),
|
_ => Err(type_error("Wrong argument format!")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, PartialEq, Debug)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum DnsReturnRecord {
|
||||||
|
A(String),
|
||||||
|
AAAA(String),
|
||||||
|
ANAME(String),
|
||||||
|
CNAME(String),
|
||||||
|
MX {
|
||||||
|
preference: u16,
|
||||||
|
exchange: String,
|
||||||
|
},
|
||||||
|
PTR(String),
|
||||||
|
SRV {
|
||||||
|
priority: u16,
|
||||||
|
weight: u16,
|
||||||
|
port: u16,
|
||||||
|
target: String,
|
||||||
|
},
|
||||||
|
TXT(Vec<String>),
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn op_dns_resolve(
|
||||||
|
state: Rc<RefCell<OpState>>,
|
||||||
|
args: Value,
|
||||||
|
_zero_copy: BufVec,
|
||||||
|
) -> Result<Value, AnyError> {
|
||||||
|
fn default_port() -> u16 {
|
||||||
|
53
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct ResolveAddrArgs {
|
||||||
|
query: String,
|
||||||
|
record_type: RecordType,
|
||||||
|
options: Option<ResolveDnsOption>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct ResolveDnsOption {
|
||||||
|
name_server: Option<NameServer>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct NameServer {
|
||||||
|
ip_addr: String,
|
||||||
|
#[serde(default = "default_port")]
|
||||||
|
port: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
let ResolveAddrArgs {
|
||||||
|
query,
|
||||||
|
record_type,
|
||||||
|
options,
|
||||||
|
} = serde_json::from_value(args)?;
|
||||||
|
|
||||||
|
let (config, opts) = if let Some(name_server) =
|
||||||
|
options.as_ref().and_then(|o| o.name_server.as_ref())
|
||||||
|
{
|
||||||
|
let group = NameServerConfigGroup::from_ips_clear(
|
||||||
|
&[name_server.ip_addr.parse()?],
|
||||||
|
name_server.port,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
(
|
||||||
|
ResolverConfig::from_parts(None, vec![], group),
|
||||||
|
ResolverOpts::default(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
system_conf::read_system_conf()?
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
let s = state.borrow();
|
||||||
|
let perm = s.borrow::<Permissions>();
|
||||||
|
|
||||||
|
// Checks permission against the name servers which will be actually queried.
|
||||||
|
for ns in config.name_servers() {
|
||||||
|
let socker_addr = &ns.socket_addr;
|
||||||
|
let ip = socker_addr.ip().to_string();
|
||||||
|
let port = socker_addr.port();
|
||||||
|
perm.check_net(&(ip, Some(port)))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let resolver = AsyncResolver::tokio(config, opts)?;
|
||||||
|
|
||||||
|
let results: Vec<DnsReturnRecord> = resolver
|
||||||
|
.lookup(query, record_type, Default::default())
|
||||||
|
.await?
|
||||||
|
.iter()
|
||||||
|
.filter_map(rdata_to_return_record(record_type))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(json!(results))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rdata_to_return_record(
|
||||||
|
ty: RecordType,
|
||||||
|
) -> impl Fn(&RData) -> Option<DnsReturnRecord> {
|
||||||
|
use RecordType::*;
|
||||||
|
move |r: &RData| -> Option<DnsReturnRecord> {
|
||||||
|
match ty {
|
||||||
|
A => r.as_a().map(ToString::to_string).map(DnsReturnRecord::A),
|
||||||
|
AAAA => r
|
||||||
|
.as_aaaa()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.map(DnsReturnRecord::AAAA),
|
||||||
|
ANAME => r
|
||||||
|
.as_aname()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.map(DnsReturnRecord::ANAME),
|
||||||
|
CNAME => r
|
||||||
|
.as_cname()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.map(DnsReturnRecord::CNAME),
|
||||||
|
MX => r.as_mx().map(|mx| DnsReturnRecord::MX {
|
||||||
|
preference: mx.preference(),
|
||||||
|
exchange: mx.exchange().to_string(),
|
||||||
|
}),
|
||||||
|
PTR => r
|
||||||
|
.as_ptr()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.map(DnsReturnRecord::PTR),
|
||||||
|
SRV => r.as_srv().map(|srv| DnsReturnRecord::SRV {
|
||||||
|
priority: srv.priority(),
|
||||||
|
weight: srv.weight(),
|
||||||
|
port: srv.port(),
|
||||||
|
target: srv.target().to_string(),
|
||||||
|
}),
|
||||||
|
TXT => r.as_txt().map(|txt| {
|
||||||
|
let texts: Vec<String> = txt
|
||||||
|
.iter()
|
||||||
|
.map(|bytes| {
|
||||||
|
// Tries to parse these bytes as Latin-1
|
||||||
|
bytes.iter().map(|&b| b as char).collect::<String>()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
DnsReturnRecord::TXT(texts)
|
||||||
|
}),
|
||||||
|
// TODO(magurotuna): Other record types are not supported
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
use std::net::Ipv6Addr;
|
||||||
|
use trust_dns_proto::rr::rdata::mx::MX;
|
||||||
|
use trust_dns_proto::rr::rdata::srv::SRV;
|
||||||
|
use trust_dns_proto::rr::rdata::txt::TXT;
|
||||||
|
use trust_dns_proto::rr::record_data::RData;
|
||||||
|
use trust_dns_proto::rr::Name;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rdata_to_return_record_a() {
|
||||||
|
let func = rdata_to_return_record(RecordType::A);
|
||||||
|
let rdata = RData::A(Ipv4Addr::new(127, 0, 0, 1));
|
||||||
|
assert_eq!(
|
||||||
|
func(&rdata),
|
||||||
|
Some(DnsReturnRecord::A("127.0.0.1".to_string()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rdata_to_return_record_aaaa() {
|
||||||
|
let func = rdata_to_return_record(RecordType::AAAA);
|
||||||
|
let rdata = RData::AAAA(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
|
||||||
|
assert_eq!(func(&rdata), Some(DnsReturnRecord::AAAA("::1".to_string())));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rdata_to_return_record_aname() {
|
||||||
|
let func = rdata_to_return_record(RecordType::ANAME);
|
||||||
|
let rdata = RData::ANAME(Name::new());
|
||||||
|
assert_eq!(func(&rdata), Some(DnsReturnRecord::ANAME("".to_string())));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rdata_to_return_record_cname() {
|
||||||
|
let func = rdata_to_return_record(RecordType::CNAME);
|
||||||
|
let rdata = RData::CNAME(Name::new());
|
||||||
|
assert_eq!(func(&rdata), Some(DnsReturnRecord::CNAME("".to_string())));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rdata_to_return_record_mx() {
|
||||||
|
let func = rdata_to_return_record(RecordType::MX);
|
||||||
|
let rdata = RData::MX(MX::new(10, Name::new()));
|
||||||
|
assert_eq!(
|
||||||
|
func(&rdata),
|
||||||
|
Some(DnsReturnRecord::MX {
|
||||||
|
preference: 10,
|
||||||
|
exchange: "".to_string()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rdata_to_return_record_ptr() {
|
||||||
|
let func = rdata_to_return_record(RecordType::PTR);
|
||||||
|
let rdata = RData::PTR(Name::new());
|
||||||
|
assert_eq!(func(&rdata), Some(DnsReturnRecord::PTR("".to_string())));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rdata_to_return_record_srv() {
|
||||||
|
let func = rdata_to_return_record(RecordType::SRV);
|
||||||
|
let rdata = RData::SRV(SRV::new(1, 2, 3, Name::new()));
|
||||||
|
assert_eq!(
|
||||||
|
func(&rdata),
|
||||||
|
Some(DnsReturnRecord::SRV {
|
||||||
|
priority: 1,
|
||||||
|
weight: 2,
|
||||||
|
port: 3,
|
||||||
|
target: "".to_string()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rdata_to_return_record_txt() {
|
||||||
|
let func = rdata_to_return_record(RecordType::TXT);
|
||||||
|
let rdata = RData::TXT(TXT::from_bytes(vec![
|
||||||
|
"foo".as_bytes(),
|
||||||
|
"bar".as_bytes(),
|
||||||
|
&[0xa3], // "£" in Latin-1
|
||||||
|
&[0xe3, 0x81, 0x82], // "あ" in UTF-8
|
||||||
|
]));
|
||||||
|
assert_eq!(
|
||||||
|
func(&rdata),
|
||||||
|
Some(DnsReturnRecord::TXT(vec![
|
||||||
|
"foo".to_string(),
|
||||||
|
"bar".to_string(),
|
||||||
|
"£".to_string(),
|
||||||
|
"ã\u{81}\u{82}".to_string(),
|
||||||
|
]))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -818,7 +818,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_check_net() {
|
fn test_check_net_with_values() {
|
||||||
let perms = Permissions::from_options(&PermissionsOptions {
|
let perms = Permissions::from_options(&PermissionsOptions {
|
||||||
allow_net: Some(svec![
|
allow_net: Some(svec![
|
||||||
"localhost",
|
"localhost",
|
||||||
|
@ -854,6 +854,93 @@ mod tests {
|
||||||
("192.168.0.1", 0, false),
|
("192.168.0.1", 0, false),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
for (host, port, is_ok) in domain_tests {
|
||||||
|
assert_eq!(is_ok, perms.check_net(&(host, Some(port))).is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_check_net_only_flag() {
|
||||||
|
let perms = Permissions::from_options(&PermissionsOptions {
|
||||||
|
allow_net: Some(svec![]), // this means `--allow-net` is present without values following `=` sign
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
let domain_tests = vec![
|
||||||
|
("localhost", 1234),
|
||||||
|
("deno.land", 0),
|
||||||
|
("deno.land", 3000),
|
||||||
|
("deno.lands", 0),
|
||||||
|
("deno.lands", 3000),
|
||||||
|
("github.com", 3000),
|
||||||
|
("github.com", 0),
|
||||||
|
("github.com", 2000),
|
||||||
|
("github.net", 3000),
|
||||||
|
("127.0.0.1", 0),
|
||||||
|
("127.0.0.1", 3000),
|
||||||
|
("127.0.0.2", 0),
|
||||||
|
("127.0.0.2", 3000),
|
||||||
|
("172.16.0.2", 8000),
|
||||||
|
("172.16.0.2", 0),
|
||||||
|
("172.16.0.2", 6000),
|
||||||
|
("172.16.0.1", 8000),
|
||||||
|
("somedomain", 0),
|
||||||
|
("192.168.0.1", 0),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (host, port) in domain_tests {
|
||||||
|
assert!(perms.check_net(&(host, Some(port))).is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_check_net_no_flag() {
|
||||||
|
let perms = Permissions::from_options(&PermissionsOptions {
|
||||||
|
allow_net: None,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
let domain_tests = vec![
|
||||||
|
("localhost", 1234),
|
||||||
|
("deno.land", 0),
|
||||||
|
("deno.land", 3000),
|
||||||
|
("deno.lands", 0),
|
||||||
|
("deno.lands", 3000),
|
||||||
|
("github.com", 3000),
|
||||||
|
("github.com", 0),
|
||||||
|
("github.com", 2000),
|
||||||
|
("github.net", 3000),
|
||||||
|
("127.0.0.1", 0),
|
||||||
|
("127.0.0.1", 3000),
|
||||||
|
("127.0.0.2", 0),
|
||||||
|
("127.0.0.2", 3000),
|
||||||
|
("172.16.0.2", 8000),
|
||||||
|
("172.16.0.2", 0),
|
||||||
|
("172.16.0.2", 6000),
|
||||||
|
("172.16.0.1", 8000),
|
||||||
|
("somedomain", 0),
|
||||||
|
("192.168.0.1", 0),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (host, port) in domain_tests {
|
||||||
|
assert!(!perms.check_net(&(host, Some(port))).is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_check_net_url() {
|
||||||
|
let perms = Permissions::from_options(&PermissionsOptions {
|
||||||
|
allow_net: Some(svec![
|
||||||
|
"localhost",
|
||||||
|
"deno.land",
|
||||||
|
"github.com:3000",
|
||||||
|
"127.0.0.1",
|
||||||
|
"172.16.0.2:8000",
|
||||||
|
"www.github.com:443"
|
||||||
|
]),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
|
||||||
let url_tests = vec![
|
let url_tests = vec![
|
||||||
// Any protocol + port for localhost should be ok, since we don't specify
|
// Any protocol + port for localhost should be ok, since we don't specify
|
||||||
("http://localhost", true),
|
("http://localhost", true),
|
||||||
|
@ -893,13 +980,9 @@ mod tests {
|
||||||
("https://www.github.com:443/robots.txt", true),
|
("https://www.github.com:443/robots.txt", true),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (url_str, is_ok) in url_tests.iter() {
|
for (url_str, is_ok) in url_tests {
|
||||||
let u = url::Url::parse(url_str).unwrap();
|
let u = url::Url::parse(url_str).unwrap();
|
||||||
assert_eq!(*is_ok, perms.check_net_url(&u).is_ok());
|
assert_eq!(is_ok, perms.check_net_url(&u).is_ok());
|
||||||
}
|
|
||||||
|
|
||||||
for (hostname, port, is_ok) in domain_tests.iter() {
|
|
||||||
assert_eq!(*is_ok, perms.check_net(&(hostname, Some(*port))).is_ok());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
use core::mem::replace;
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
@ -28,6 +27,7 @@ use std::env;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use std::mem::replace;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
Loading…
Reference in a new issue