From 4acca8ed84fed08d62c94205ef6cb738239d2bcf Mon Sep 17 00:00:00 2001 From: Paolo Insogna Date: Wed, 17 Apr 2024 17:24:28 +0200 Subject: [PATCH] dns: add order option and support ipv6first PR-URL: https://github.com/nodejs/node/pull/52492 Reviewed-By: Matteo Collina Reviewed-By: Marco Ippolito --- doc/api/cli.md | 10 ++- doc/api/dns.md | 66 ++++++++++++---- lib/dns.js | 26 +++++-- lib/internal/dns/promises.js | 36 ++++++--- lib/internal/dns/utils.js | 8 +- lib/internal/modules/esm/fetch_module.js | 2 +- src/cares_wrap.cc | 76 ++++++++++++++----- src/cares_wrap.h | 9 ++- src/node_options.cc | 1 + .../test-dns-getDefaultResultOrder.js | 21 ++++- test/internet/test-dns.js | 2 +- test/parallel/test-dns-default-order-ipv4.js | 49 ++++++++++++ test/parallel/test-dns-default-order-ipv6.js | 49 ++++++++++++ .../test-dns-default-order-verbatim.js | 49 ++++++++++++ .../test-dns-default-verbatim-false.js | 8 +- .../test-dns-default-verbatim-true.js | 8 +- ...-dns-lookup-promises-options-deprecated.js | 2 + test/parallel/test-dns-lookup.js | 9 +++ test/parallel/test-dns-perf_hooks.js | 1 + test/parallel/test-dns-set-default-order.js | 60 ++++++++++----- test/parallel/test-dns.js | 2 +- 21 files changed, 403 insertions(+), 91 deletions(-) create mode 100644 test/parallel/test-dns-default-order-ipv4.js create mode 100644 test/parallel/test-dns-default-order-ipv6.js create mode 100644 test/parallel/test-dns-default-order-verbatim.js diff --git a/doc/api/cli.md b/doc/api/cli.md index acb25165c4f756..69bfd23002fe30 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -588,16 +588,20 @@ added: - v16.4.0 - v14.18.0 changes: + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/52492 + description: The `ipv6first` is supported now. - version: v17.0.0 pr-url: https://github.com/nodejs/node/pull/39987 description: Changed default value to `verbatim`. --> -Set the default value of `verbatim` in [`dns.lookup()`][] and +Set the default value of `order` in [`dns.lookup()`][] and [`dnsPromises.lookup()`][]. The value could be: -* `ipv4first`: sets default `verbatim` `false`. -* `verbatim`: sets default `verbatim` `true`. +* `ipv4first`: sets default `order` to `ipv4first`. +* `ipv6first`: sets default `order` to `ipv6first`. +* `verbatim`: sets default `order` to `verbatim`. The default is `verbatim` and [`dns.setDefaultResultOrder()`][] have higher priority than `--dns-result-order`. diff --git a/doc/api/dns.md b/doc/api/dns.md index 0c16767f336afe..b89da8e331e3fd 100644 --- a/doc/api/dns.md +++ b/doc/api/dns.md @@ -179,6 +179,9 @@ section if a custom port is used. -* `order` {string} must be `'ipv4first'` or `'verbatim'`. +* `order` {string} must be `'ipv4first'`, `'ipv6first'` or `'verbatim'`. -Set the default value of `verbatim` in [`dns.lookup()`][] and +Set the default value of `order` in [`dns.lookup()`][] and [`dnsPromises.lookup()`][]. The value could be: -* `ipv4first`: sets default `verbatim` `false`. -* `verbatim`: sets default `verbatim` `true`. +* `ipv4first`: sets default `order` to `ipv4first`. +* `ipv6first`: sets default `order` to `ipv6first`. +* `verbatim`: sets default `order` to `verbatim`. The default is `verbatim` and [`dns.setDefaultResultOrder()`][] have higher priority than [`--dns-result-order`][]. When using [worker threads][], @@ -796,14 +812,21 @@ dns orders in workers. ## `dns.getDefaultResultOrder()` -Get the default value for `verbatim` in [`dns.lookup()`][] and +Get the default value for `order` in [`dns.lookup()`][] and [`dnsPromises.lookup()`][]. The value could be: -* `ipv4first`: for `verbatim` defaulting to `false`. -* `verbatim`: for `verbatim` defaulting to `true`. +* `ipv4first`: for `order` defaulting to `ipv4first`. +* `ipv6first`: for `order` defaulting to `ipv6first`. +* `verbatim`: for `order` defaulting to `verbatim`. ## `dns.setServers(servers)` @@ -947,6 +970,10 @@ section if a custom port is used. * `hostname` {string} @@ -959,13 +986,22 @@ added: v10.6.0 flags may be passed by bitwise `OR`ing their values. * `all` {boolean} When `true`, the `Promise` is resolved with all addresses in an array. Otherwise, returns a single address. **Default:** `false`. + * `order` {string} When `verbatim`, the `Promise` is resolved with IPv4 and + IPv6 addresses in the order the DNS resolver returned them. When `ipv4first`, + IPv4 addresses are placed before IPv6 addresses. When `ipv6first`, + IPv6 addresses are placed before IPv4 addresses. + **Default:** `verbatim` (addresses are not reordered). + Default value is configurable using [`dns.setDefaultResultOrder()`][] or + [`--dns-result-order`][]. New code should use `{ order: 'verbatim' }`. * `verbatim` {boolean} When `true`, the `Promise` is resolved with IPv4 and IPv6 addresses in the order the DNS resolver returned them. When `false`, IPv4 addresses are placed before IPv6 addresses. + This option will be deprecated in favor of `order`. When both are specified, + `order` has higher precedence. New code should only use `order`. **Default:** currently `false` (addresses are reordered) but this is expected to change in the not too distant future. Default value is configurable using [`dns.setDefaultResultOrder()`][] or - [`--dns-result-order`][]. New code should use `{ verbatim: true }`. + [`--dns-result-order`][]. Resolves a host name (e.g. `'nodejs.org'`) into the first found A (IPv4) or AAAA (IPv6) record. All `option` properties are optional. If `options` is an @@ -1347,18 +1383,22 @@ added: - v16.4.0 - v14.18.0 changes: + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/52492 + description: The `ipv6first` value is supported now. - version: v17.0.0 pr-url: https://github.com/nodejs/node/pull/39987 description: Changed default value to `verbatim`. --> -* `order` {string} must be `'ipv4first'` or `'verbatim'`. +* `order` {string} must be `'ipv4first'`, `'ipv6first'` or `'verbatim'`. -Set the default value of `verbatim` in [`dns.lookup()`][] and +Set the default value of `order` in [`dns.lookup()`][] and [`dnsPromises.lookup()`][]. The value could be: -* `ipv4first`: sets default `verbatim` `false`. -* `verbatim`: sets default `verbatim` `true`. +* `ipv4first`: sets default `order` to `ipv4first`. +* `ipv6first`: sets default `order` to `ipv6first`. +* `verbatim`: sets default `order` to `verbatim`. The default is `verbatim` and [`dnsPromises.setDefaultResultOrder()`][] have higher priority than [`--dns-result-order`][]. When using [worker threads][], diff --git a/lib/dns.js b/lib/dns.js index 681f0aa3e58ecf..9924f07f41947b 100644 --- a/lib/dns.js +++ b/lib/dns.js @@ -43,7 +43,6 @@ const { setDefaultResolver, validateHints, emitInvalidHostnameWarning, - getDefaultVerbatim, getDefaultResultOrder, setDefaultResultOrder, errorCodes: dnsErrorCodes, @@ -89,6 +88,9 @@ const { const { GetAddrInfoReqWrap, GetNameInfoReqWrap, + DNS_ORDER_VERBATIM, + DNS_ORDER_IPV4_FIRST, + DNS_ORDER_IPV6_FIRST, } = cares; const kPerfHooksDnsLookupContext = Symbol('kPerfHooksDnsLookupContext'); @@ -141,7 +143,7 @@ function lookup(hostname, options, callback) { let hints = 0; let family = 0; let all = false; - let verbatim = getDefaultVerbatim(); + let dnsOrder = getDefaultResultOrder(); // Parse arguments if (hostname) { @@ -187,7 +189,11 @@ function lookup(hostname, options, callback) { } if (options?.verbatim != null) { validateBoolean(options.verbatim, 'options.verbatim'); - verbatim = options.verbatim; + dnsOrder = options.verbatim ? 'verbatim' : 'ipv4first'; + } + if (options?.order != null) { + validateOneOf(options.order, 'options.order', ['ipv4first', 'ipv6first', 'verbatim']); + dnsOrder = options.dnsOrder; } } @@ -218,8 +224,16 @@ function lookup(hostname, options, callback) { req.hostname = hostname; req.oncomplete = all ? onlookupall : onlookup; + let order = DNS_ORDER_VERBATIM; + + if (dnsOrder === 'ipv4first') { + order = DNS_ORDER_IPV4_FIRST; + } else if (dnsOrder === 'ipv6first') { + order = DNS_ORDER_IPV6_FIRST; + } + const err = cares.getaddrinfo( - req, hostname, family, hints, verbatim, + req, hostname, family, hints, order, ); if (err) { process.nextTick(callback, new DNSException(err, 'getaddrinfo', hostname)); @@ -230,8 +244,10 @@ function lookup(hostname, options, callback) { hostname, family, hints, - verbatim, + verbatim: order === DNS_ORDER_VERBATIM, + order: dnsOrder, }; + startPerf(req, kPerfHooksDnsLookupContext, { type: 'dns', name: 'lookup', detail }); } return req; diff --git a/lib/internal/dns/promises.js b/lib/internal/dns/promises.js index 56276fdbae7db7..602ff447fd31f5 100644 --- a/lib/internal/dns/promises.js +++ b/lib/internal/dns/promises.js @@ -12,7 +12,6 @@ const { createResolverClass, validateHints, emitInvalidHostnameWarning, - getDefaultVerbatim, errorCodes: dnsErrorCodes, getDefaultResultOrder, setDefaultResultOrder, @@ -53,6 +52,9 @@ const { GetAddrInfoReqWrap, GetNameInfoReqWrap, QueryReqWrap, + DNS_ORDER_VERBATIM, + DNS_ORDER_IPV4_FIRST, + DNS_ORDER_IPV6_FIRST, } = internalBinding('cares_wrap'); const { ERR_INVALID_ARG_TYPE, @@ -120,13 +122,13 @@ function onlookupall(err, addresses) { * @param {boolean} all - Whether to resolve with all IP addresses for the hostname. * @param {number} hints - One or more supported getaddrinfo flags (supply multiple via * bitwise OR). - * @param {boolean} verbatim - Whether to use the hostname verbatim. + * @param {number} dnsOrder - How to sort results. Must be `ipv4first`, `ipv6first` or `verbatim`. * @returns {Promise} The IP address(es) of the hostname. * @typedef {object} DNSLookupResult * @property {string} address - The IP address. * @property {0 | 4 | 6} family - The IP address type. 4 for IPv4 or 6 for IPv6, or 0 (for both). */ -function createLookupPromise(family, hostname, all, hints, verbatim) { +function createLookupPromise(family, hostname, all, hints, dnsOrder) { return new Promise((resolve, reject) => { if (!hostname) { emitInvalidHostnameWarning(hostname); @@ -150,7 +152,15 @@ function createLookupPromise(family, hostname, all, hints, verbatim) { req.resolve = resolve; req.reject = reject; - const err = getaddrinfo(req, hostname, family, hints, verbatim); + let order = DNS_ORDER_VERBATIM; + + if (dnsOrder === 'ipv4first') { + order = DNS_ORDER_IPV4_FIRST; + } else if (dnsOrder === 'ipv6first') { + order = DNS_ORDER_IPV6_FIRST; + } + + const err = getaddrinfo(req, hostname, family, hints, order); if (err) { reject(new DNSException(err, 'getaddrinfo', hostname)); @@ -159,7 +169,8 @@ function createLookupPromise(family, hostname, all, hints, verbatim) { hostname, family, hints, - verbatim, + verbatim: order === DNS_ORDER_VERBATIM, + order: dnsOrder, }; startPerf(req, kPerfHooksDnsLookupContext, { type: 'dns', name: 'lookup', detail }); } @@ -175,14 +186,15 @@ const validFamilies = [0, 4, 6]; * @param {0 | 4 | 6} [options.family=0] - The record family. Must be 4, 6, or 0 (for both). * @param {number} [options.hints] - One or more supported getaddrinfo flags (supply multiple via * bitwise OR). - * @param {boolean} [options.verbatim=false] - Return results in same order DNS resolved them; - * otherwise IPv4 then IPv6. New code should supply `true`. + * @param {string} [options.order='verbatim'] - Return results in same order DNS resolved them; + * Must be `ipv4first`, `ipv6first` or `verbatim`. + * New code should supply `verbatim`. */ function lookup(hostname, options) { let hints = 0; let family = 0; let all = false; - let verbatim = getDefaultVerbatim(); + let dnsOrder = getDefaultResultOrder(); // Parse arguments if (hostname) { @@ -210,11 +222,15 @@ function lookup(hostname, options) { } if (options?.verbatim != null) { validateBoolean(options.verbatim, 'options.verbatim'); - verbatim = options.verbatim; + dnsOrder = options.verbatim ? 'verbatim' : 'ipv4first'; + } + if (options?.order != null) { + validateOneOf(options.order, 'options.order', ['ipv4first', 'ipv6first', 'verbatim']); + dnsOrder = options.order; } } - return createLookupPromise(family, hostname, all, hints, verbatim); + return createLookupPromise(family, hostname, all, hints, dnsOrder); } diff --git a/lib/internal/dns/utils.js b/lib/internal/dns/utils.js index 0d1f817593f2e7..a79a5b846a6d18 100644 --- a/lib/internal/dns/utils.js +++ b/lib/internal/dns/utils.js @@ -207,6 +207,7 @@ function initializeDns() { dnsOrder ??= 'verbatim'; } else { // Allow the deserialized application to override order from CLI. + validateOneOf(orderFromCLI, '--dns-result-order', ['verbatim', 'ipv4first', 'ipv6first']); dnsOrder = orderFromCLI; } @@ -277,12 +278,8 @@ function emitInvalidHostnameWarning(hostname) { } } -function getDefaultVerbatim() { - return dnsOrder !== 'ipv4first'; -} - function setDefaultResultOrder(value) { - validateOneOf(value, 'dnsOrder', ['verbatim', 'ipv4first']); + validateOneOf(value, 'dnsOrder', ['verbatim', 'ipv4first', 'ipv6first']); dnsOrder = value; } @@ -351,7 +348,6 @@ module.exports = { validateTimeout, validateTries, emitInvalidHostnameWarning, - getDefaultVerbatim, getDefaultResultOrder, setDefaultResultOrder, errorCodes, diff --git a/lib/internal/modules/esm/fetch_module.js b/lib/internal/modules/esm/fetch_module.js index b3491d97cb99c7..b6fd294eb2b624 100644 --- a/lib/internal/modules/esm/fetch_module.js +++ b/lib/internal/modules/esm/fetch_module.js @@ -253,7 +253,7 @@ async function isLocalAddress(hostname) { ) { hostname = StringPrototypeSlice(hostname, 1, -1); } - const addr = await dnsLookup(hostname, { verbatim: true }); + const addr = await dnsLookup(hostname, { order: 'verbatim' }); const ipv = addr.family === 4 ? 'ipv4' : 'ipv6'; return allowList.check(addr.address, ipv); } catch { diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index 8b037356360729..e129cc57b57af7 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -72,6 +72,7 @@ using v8::Nothing; using v8::Null; using v8::Object; using v8::String; +using v8::Uint32; using v8::Value; namespace { @@ -665,12 +666,11 @@ void ChannelWrap::New(const FunctionCallbackInfo& args) { new ChannelWrap(env, args.This(), timeout, tries); } -GetAddrInfoReqWrap::GetAddrInfoReqWrap( - Environment* env, - Local req_wrap_obj, - bool verbatim) +GetAddrInfoReqWrap::GetAddrInfoReqWrap(Environment* env, + Local req_wrap_obj, + uint8_t order) : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETADDRINFOREQWRAP), - verbatim_(verbatim) {} + order_(order) {} GetNameInfoReqWrap::GetNameInfoReqWrap( Environment* env, @@ -1445,7 +1445,7 @@ void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) { }; uint32_t n = 0; - const bool verbatim = req_wrap->verbatim(); + const uint8_t order = req_wrap->order(); if (status == 0) { Local results = Array::New(env->isolate()); @@ -1477,11 +1477,21 @@ void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) { return Just(true); }; - if (add(true, verbatim).IsNothing()) - return; - if (verbatim == false) { - if (add(false, true).IsNothing()) - return; + switch (order) { + case DNS_ORDER_IPV4_FIRST: + if (add(true, false).IsNothing()) return; + if (add(false, true).IsNothing()) return; + + break; + case DNS_ORDER_IPV6_FIRST: + if (add(false, true).IsNothing()) return; + if (add(true, false).IsNothing()) return; + + break; + default: + if (add(true, true).IsNothing()) return; + + break; } // No responses were found to return @@ -1492,9 +1502,13 @@ void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) { argv[1] = results; } - TRACE_EVENT_NESTABLE_ASYNC_END2( - TRACING_CATEGORY_NODE2(dns, native), "lookup", req_wrap.get(), - "count", n, "verbatim", verbatim); + TRACE_EVENT_NESTABLE_ASYNC_END2(TRACING_CATEGORY_NODE2(dns, native), + "lookup", + req_wrap.get(), + "count", + n, + "order", + order); // Make the callback into JavaScript req_wrap->MakeCallback(env->oncomplete_string(), arraysize(argv), argv); @@ -1558,7 +1572,7 @@ void GetAddrInfo(const FunctionCallbackInfo& args) { CHECK(args[0]->IsObject()); CHECK(args[1]->IsString()); CHECK(args[2]->IsInt32()); - CHECK(args[4]->IsBoolean()); + CHECK(args[4]->IsUint32()); Local req_wrap_obj = args[0].As(); node::Utf8Value hostname(env->isolate(), args[1]); std::string ascii_hostname = ada::idna::to_ascii(hostname.ToStringView()); @@ -1584,9 +1598,10 @@ void GetAddrInfo(const FunctionCallbackInfo& args) { UNREACHABLE("bad address family"); } - auto req_wrap = std::make_unique(env, - req_wrap_obj, - args[4]->IsTrue()); + Local order = args[4].As(); + + auto req_wrap = + std::make_unique(env, req_wrap_obj, order->Value()); struct addrinfo hints; memset(&hints, 0, sizeof(hints)); @@ -1905,6 +1920,31 @@ void Initialize(Local target, target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), "AI_V4MAPPED"), Integer::New(env->isolate(), AI_V4MAPPED)).Check(); + target + ->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "DNS_ORDER_VERBATIM"), + Integer::New(env->isolate(), DNS_ORDER_VERBATIM)) + .Check(); + target + ->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "DNS_ORDER_IPV4_FIRST"), + Integer::New(env->isolate(), DNS_ORDER_IPV4_FIRST)) + .Check(); + target + ->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "DNS_ORDER_IPV6_FIRST"), + Integer::New(env->isolate(), DNS_ORDER_IPV6_FIRST)) + .Check(); + target + ->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET"), + Integer::New(env->isolate(), AF_INET)) + .Check(); + target + ->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET"), + Integer::New(env->isolate(), AF_INET)) + .Check(); Local aiw = BaseObject::MakeLazilyInitializedJSTemplate(env); diff --git a/src/cares_wrap.h b/src/cares_wrap.h index ea339b773991e4..021ef1c9de518e 100644 --- a/src/cares_wrap.h +++ b/src/cares_wrap.h @@ -30,6 +30,9 @@ namespace cares_wrap { constexpr int ns_t_cname_or_a = -1; constexpr int DNS_ESETSRVPENDING = -1000; +constexpr uint8_t DNS_ORDER_VERBATIM = 0; +constexpr uint8_t DNS_ORDER_IPV4_FIRST = 1; +constexpr uint8_t DNS_ORDER_IPV6_FIRST = 2; class ChannelWrap; @@ -195,16 +198,16 @@ class GetAddrInfoReqWrap final : public ReqWrap { public: GetAddrInfoReqWrap(Environment* env, v8::Local req_wrap_obj, - bool verbatim); + uint8_t order); SET_NO_MEMORY_INFO() SET_MEMORY_INFO_NAME(GetAddrInfoReqWrap) SET_SELF_SIZE(GetAddrInfoReqWrap) - bool verbatim() const { return verbatim_; } + uint8_t order() const { return order_; } private: - const bool verbatim_; + const uint8_t order_; }; class GetNameInfoReqWrap final : public ReqWrap { diff --git a/src/node_options.cc b/src/node_options.cc index 8d046d8922f102..556b3c1592e056 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -360,6 +360,7 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { AddOption("--dns-result-order", "set default value of verbatim in dns.lookup. Options are " "'ipv4first' (IPv4 addresses are placed before IPv6 addresses) " + "'ipv6first' (IPv6 addresses are placed before IPv4 addresses) " "'verbatim' (addresses are in the order the DNS resolver " "returned)", &EnvironmentOptions::dns_result_order, diff --git a/test/internet/test-dns-getDefaultResultOrder.js b/test/internet/test-dns-getDefaultResultOrder.js index ae176f1264508b..86216e9a14a0f4 100644 --- a/test/internet/test-dns-getDefaultResultOrder.js +++ b/test/internet/test-dns-getDefaultResultOrder.js @@ -8,6 +8,9 @@ const dns = require('dns'); dns.setDefaultResultOrder('ipv4first'); let dnsOrder = dns.getDefaultResultOrder(); assert.ok(dnsOrder === 'ipv4first'); +dns.setDefaultResultOrder('ipv6first'); +dnsOrder = dns.getDefaultResultOrder(); +assert.ok(dnsOrder === 'ipv6first'); dns.setDefaultResultOrder('verbatim'); dnsOrder = dns.getDefaultResultOrder(); assert.ok(dnsOrder === 'verbatim'); @@ -15,10 +18,26 @@ assert.ok(dnsOrder === 'verbatim'); { (async function() { const result = await dns.promises.lookup('localhost'); - const result1 = await dns.promises.lookup('localhost', { verbatim: true }); + const result1 = await dns.promises.lookup('localhost', { order: 'verbatim' }); assert.ok(result !== undefined); assert.ok(result1 !== undefined); assert.ok(result.address === result1.address); assert.ok(result.family === result1.family); })().then(common.mustCall()); } + +{ + (async function() { + const result = await dns.promises.lookup('localhost', { order: 'ipv4first' }); + assert.ok(result !== undefined); + assert.ok(result.family === 4); + })().then(common.mustCall()); +} + +if (common.hasIPv6) { + (async function() { + const result = await dns.promises.lookup('localhost', { order: 'ipv6first' }); + assert.ok(result !== undefined); + assert.ok(result.family === 6); + })().then(common.mustCall()); +} diff --git a/test/internet/test-dns.js b/test/internet/test-dns.js index 090a376e8b2463..abf94314b1b266 100644 --- a/test/internet/test-dns.js +++ b/test/internet/test-dns.js @@ -722,7 +722,7 @@ console.log(`looking up ${addresses.INET4_HOST}..`); const cares = internalBinding('cares_wrap'); const req = new cares.GetAddrInfoReqWrap(); cares.getaddrinfo(req, addresses.INET4_HOST, 4, - /* hints */ 0, /* verbatim */ true); + /* hints */ 0, /* order */ cares.DNS_ORDER_VERBATIM); req.oncomplete = function(err, domains) { assert.strictEqual(err, 0); diff --git a/test/parallel/test-dns-default-order-ipv4.js b/test/parallel/test-dns-default-order-ipv4.js new file mode 100644 index 00000000000000..9340d4cdb9ffde --- /dev/null +++ b/test/parallel/test-dns-default-order-ipv4.js @@ -0,0 +1,49 @@ +// Flags: --expose-internals --dns-result-order=ipv4first +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const { internalBinding } = require('internal/test/binding'); +const cares = internalBinding('cares_wrap'); +const { promisify } = require('util'); + +// Test that --dns-result-order=ipv4first works as expected. + +const originalGetaddrinfo = cares.getaddrinfo; +const calls = []; +cares.getaddrinfo = common.mustCallAtLeast((...args) => { + calls.push(args); + originalGetaddrinfo(...args); +}, 1); + +const dns = require('dns'); +const dnsPromises = dns.promises; + +// We want to test the parameter of order only so that we +// ignore possible errors here. +function allowFailed(fn) { + return fn.catch((_err) => { + // + }); +} + +(async () => { + let callsLength = 0; + const checkParameter = (expected) => { + assert.strictEqual(calls.length, callsLength + 1); + const order = calls[callsLength][4]; + assert.strictEqual(order, expected); + callsLength += 1; + }; + + await allowFailed(promisify(dns.lookup)('example.org')); + checkParameter(cares.DNS_ORDER_IPV4_FIRST); + + await allowFailed(dnsPromises.lookup('example.org')); + checkParameter(cares.DNS_ORDER_IPV4_FIRST); + + await allowFailed(promisify(dns.lookup)('example.org', {})); + checkParameter(cares.DNS_ORDER_IPV4_FIRST); + + await allowFailed(dnsPromises.lookup('example.org', {})); + checkParameter(cares.DNS_ORDER_IPV4_FIRST); +})().then(common.mustCall()); diff --git a/test/parallel/test-dns-default-order-ipv6.js b/test/parallel/test-dns-default-order-ipv6.js new file mode 100644 index 00000000000000..a12f3f4d43c985 --- /dev/null +++ b/test/parallel/test-dns-default-order-ipv6.js @@ -0,0 +1,49 @@ +// Flags: --expose-internals --dns-result-order=ipv6first +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const { internalBinding } = require('internal/test/binding'); +const cares = internalBinding('cares_wrap'); +const { promisify } = require('util'); + +// Test that --dns-result-order=verbatim works as expected. + +const originalGetaddrinfo = cares.getaddrinfo; +const calls = []; +cares.getaddrinfo = common.mustCallAtLeast((...args) => { + calls.push(args); + originalGetaddrinfo(...args); +}, 1); + +const dns = require('dns'); +const dnsPromises = dns.promises; + +// We want to test the parameter of verbatim only so that we +// ignore possible errors here. +function allowFailed(fn) { + return fn.catch((_err) => { + // + }); +} + +(async () => { + let callsLength = 0; + const checkParameter = (expected) => { + assert.strictEqual(calls.length, callsLength + 1); + const order = calls[callsLength][4]; + assert.strictEqual(order, expected); + callsLength += 1; + }; + + await allowFailed(promisify(dns.lookup)('example.org')); + checkParameter(cares.DNS_ORDER_IPV6_FIRST); + + await allowFailed(dnsPromises.lookup('example.org')); + checkParameter(cares.DNS_ORDER_IPV6_FIRST); + + await allowFailed(promisify(dns.lookup)('example.org', {})); + checkParameter(cares.DNS_ORDER_IPV6_FIRST); + + await allowFailed(dnsPromises.lookup('example.org', {})); + checkParameter(cares.DNS_ORDER_IPV6_FIRST); +})().then(common.mustCall()); diff --git a/test/parallel/test-dns-default-order-verbatim.js b/test/parallel/test-dns-default-order-verbatim.js new file mode 100644 index 00000000000000..0c45728782d20a --- /dev/null +++ b/test/parallel/test-dns-default-order-verbatim.js @@ -0,0 +1,49 @@ +// Flags: --expose-internals --dns-result-order=verbatim +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const { internalBinding } = require('internal/test/binding'); +const cares = internalBinding('cares_wrap'); +const { promisify } = require('util'); + +// Test that --dns-result-order=verbatim works as expected. + +const originalGetaddrinfo = cares.getaddrinfo; +const calls = []; +cares.getaddrinfo = common.mustCallAtLeast((...args) => { + calls.push(args); + originalGetaddrinfo(...args); +}, 1); + +const dns = require('dns'); +const dnsPromises = dns.promises; + +// We want to test the parameter of verbatim only so that we +// ignore possible errors here. +function allowFailed(fn) { + return fn.catch((_err) => { + // + }); +} + +(async () => { + let callsLength = 0; + const checkParameter = (expected) => { + assert.strictEqual(calls.length, callsLength + 1); + const order = calls[callsLength][4]; + assert.strictEqual(order, expected); + callsLength += 1; + }; + + await allowFailed(promisify(dns.lookup)('example.org')); + checkParameter(cares.DNS_ORDER_VERBATIM); + + await allowFailed(dnsPromises.lookup('example.org')); + checkParameter(cares.DNS_ORDER_VERBATIM); + + await allowFailed(promisify(dns.lookup)('example.org', {})); + checkParameter(cares.DNS_ORDER_VERBATIM); + + await allowFailed(dnsPromises.lookup('example.org', {})); + checkParameter(cares.DNS_ORDER_VERBATIM); +})().then(common.mustCall()); diff --git a/test/parallel/test-dns-default-verbatim-false.js b/test/parallel/test-dns-default-verbatim-false.js index 06b8f66a610998..76f6ef0bcabd82 100644 --- a/test/parallel/test-dns-default-verbatim-false.js +++ b/test/parallel/test-dns-default-verbatim-false.js @@ -38,14 +38,14 @@ function allowFailed(fn) { }; await allowFailed(promisify(dns.lookup)('example.org')); - checkParameter(false); + checkParameter(cares.DNS_ORDER_IPV4_FIRST); await allowFailed(dnsPromises.lookup('example.org')); - checkParameter(false); + checkParameter(cares.DNS_ORDER_IPV4_FIRST); await allowFailed(promisify(dns.lookup)('example.org', {})); - checkParameter(false); + checkParameter(cares.DNS_ORDER_IPV4_FIRST); await allowFailed(dnsPromises.lookup('example.org', {})); - checkParameter(false); + checkParameter(cares.DNS_ORDER_IPV4_FIRST); })().then(common.mustCall()); diff --git a/test/parallel/test-dns-default-verbatim-true.js b/test/parallel/test-dns-default-verbatim-true.js index 1cdaa44a2dcb71..dfa0640f446412 100644 --- a/test/parallel/test-dns-default-verbatim-true.js +++ b/test/parallel/test-dns-default-verbatim-true.js @@ -38,14 +38,14 @@ function allowFailed(fn) { }; await allowFailed(promisify(dns.lookup)('example.org')); - checkParameter(true); + checkParameter(cares.DNS_ORDER_VERBATIM); await allowFailed(dnsPromises.lookup('example.org')); - checkParameter(true); + checkParameter(cares.DNS_ORDER_VERBATIM); await allowFailed(promisify(dns.lookup)('example.org', {})); - checkParameter(true); + checkParameter(cares.DNS_ORDER_VERBATIM); await allowFailed(dnsPromises.lookup('example.org', {})); - checkParameter(true); + checkParameter(cares.DNS_ORDER_VERBATIM); })().then(common.mustCall()); diff --git a/test/parallel/test-dns-lookup-promises-options-deprecated.js b/test/parallel/test-dns-lookup-promises-options-deprecated.js index 2761b616620cca..bf749fc644358a 100644 --- a/test/parallel/test-dns-lookup-promises-options-deprecated.js +++ b/test/parallel/test-dns-lookup-promises-options-deprecated.js @@ -31,5 +31,7 @@ assert.throws(() => dnsPromises.lookup('127.0.0.1', { all: 'true' }), { code: 'ERR_INVALID_ARG_TYPE' }); assert.throws(() => dnsPromises.lookup('127.0.0.1', { verbatim: 'true' }), { code: 'ERR_INVALID_ARG_TYPE' }); +assert.throws(() => dnsPromises.lookup('127.0.0.1', { order: 'true' }), + { code: 'ERR_INVALID_ARG_VALUE' }); assert.throws(() => dnsPromises.lookup('127.0.0.1', '6'), { code: 'ERR_INVALID_ARG_TYPE' }); diff --git a/test/parallel/test-dns-lookup.js b/test/parallel/test-dns-lookup.js index 2ee4ff2929624f..404c5555c5fcdf 100644 --- a/test/parallel/test-dns-lookup.js +++ b/test/parallel/test-dns-lookup.js @@ -133,6 +133,15 @@ assert.throws(() => dnsPromises.lookup(false, () => {}), }, err); }); +[0, 1, 0n, 1n, '', '0', Symbol(), {}, [], () => {}].forEach((order) => { + const err = { code: 'ERR_INVALID_ARG_VALUE' }; + const options = { order }; + assert.throws(() => { dnsPromises.lookup(false, options); }, err); + assert.throws(() => { + dns.lookup(false, options, common.mustNotCall()); + }, err); +}); + (async function() { let res; diff --git a/test/parallel/test-dns-perf_hooks.js b/test/parallel/test-dns-perf_hooks.js index 7636020bf6fe31..694b2e77249e7d 100644 --- a/test/parallel/test-dns-perf_hooks.js +++ b/test/parallel/test-dns-perf_hooks.js @@ -42,6 +42,7 @@ process.on('exit', () => { assert.strictEqual(typeof entry.detail.family, 'number'); assert.strictEqual(typeof entry.detail.hints, 'number'); assert.strictEqual(typeof entry.detail.verbatim, 'boolean'); + assert.strictEqual(typeof entry.detail.order, 'string'); assert.strictEqual(Array.isArray(entry.detail.addresses), true); break; case 'lookupService': diff --git a/test/parallel/test-dns-set-default-order.js b/test/parallel/test-dns-set-default-order.js index 43980c5dd8716c..a5c78c8e44fca4 100644 --- a/test/parallel/test-dns-set-default-order.js +++ b/test/parallel/test-dns-set-default-order.js @@ -19,9 +19,7 @@ cares.getaddrinfo = common.mustCallAtLeast((...args) => { const dns = require('dns'); const dnsPromises = dns.promises; -let verbatim; - -// We want to test the parameter of verbatim only so that we +// We want to test the parameter of order only so that we // ignore possible errors here. function allowFailed(fn) { return fn.catch((_err) => { @@ -46,48 +44,68 @@ assert.throws(() => dns.promises.setDefaultResultOrder(4), { let callsLength = 0; const checkParameter = (expected) => { assert.strictEqual(calls.length, callsLength + 1); - verbatim = calls[callsLength][4]; - assert.strictEqual(verbatim, expected); + const order = calls[callsLength][4]; + assert.strictEqual(order, expected); callsLength += 1; }; dns.setDefaultResultOrder('verbatim'); await allowFailed(promisify(dns.lookup)('example.org')); - checkParameter(true); + checkParameter(cares.DNS_ORDER_VERBATIM); await allowFailed(dnsPromises.lookup('example.org')); - checkParameter(true); + checkParameter(cares.DNS_ORDER_VERBATIM); await allowFailed(promisify(dns.lookup)('example.org', {})); - checkParameter(true); + checkParameter(cares.DNS_ORDER_VERBATIM); await allowFailed(dnsPromises.lookup('example.org', {})); - checkParameter(true); + checkParameter(cares.DNS_ORDER_VERBATIM); dns.setDefaultResultOrder('ipv4first'); await allowFailed(promisify(dns.lookup)('example.org')); - checkParameter(false); + checkParameter(cares.DNS_ORDER_IPV4_FIRST); + await allowFailed(dnsPromises.lookup('example.org')); + checkParameter(cares.DNS_ORDER_IPV4_FIRST); + await allowFailed(promisify(dns.lookup)('example.org', {})); + checkParameter(cares.DNS_ORDER_IPV4_FIRST); + await allowFailed(dnsPromises.lookup('example.org', {})); + checkParameter(cares.DNS_ORDER_IPV4_FIRST); + + dns.setDefaultResultOrder('ipv6first'); + await allowFailed(promisify(dns.lookup)('example.org')); + checkParameter(cares.DNS_ORDER_IPV6_FIRST); await allowFailed(dnsPromises.lookup('example.org')); - checkParameter(false); + checkParameter(cares.DNS_ORDER_IPV6_FIRST); await allowFailed(promisify(dns.lookup)('example.org', {})); - checkParameter(false); + checkParameter(cares.DNS_ORDER_IPV6_FIRST); await allowFailed(dnsPromises.lookup('example.org', {})); - checkParameter(false); + checkParameter(cares.DNS_ORDER_IPV6_FIRST); dns.promises.setDefaultResultOrder('verbatim'); await allowFailed(promisify(dns.lookup)('example.org')); - checkParameter(true); + checkParameter(cares.DNS_ORDER_VERBATIM); await allowFailed(dnsPromises.lookup('example.org')); - checkParameter(true); + checkParameter(cares.DNS_ORDER_VERBATIM); await allowFailed(promisify(dns.lookup)('example.org', {})); - checkParameter(true); + checkParameter(cares.DNS_ORDER_VERBATIM); await allowFailed(dnsPromises.lookup('example.org', {})); - checkParameter(true); + checkParameter(cares.DNS_ORDER_VERBATIM); dns.promises.setDefaultResultOrder('ipv4first'); await allowFailed(promisify(dns.lookup)('example.org')); - checkParameter(false); + checkParameter(cares.DNS_ORDER_IPV4_FIRST); + await allowFailed(dnsPromises.lookup('example.org')); + checkParameter(cares.DNS_ORDER_IPV4_FIRST); + await allowFailed(promisify(dns.lookup)('example.org', {})); + checkParameter(cares.DNS_ORDER_IPV4_FIRST); + await allowFailed(dnsPromises.lookup('example.org', {})); + checkParameter(cares.DNS_ORDER_IPV4_FIRST); + + dns.promises.setDefaultResultOrder('ipv6first'); + await allowFailed(promisify(dns.lookup)('example.org')); + checkParameter(cares.DNS_ORDER_IPV6_FIRST); await allowFailed(dnsPromises.lookup('example.org')); - checkParameter(false); + checkParameter(cares.DNS_ORDER_IPV6_FIRST); await allowFailed(promisify(dns.lookup)('example.org', {})); - checkParameter(false); + checkParameter(cares.DNS_ORDER_IPV6_FIRST); await allowFailed(dnsPromises.lookup('example.org', {})); - checkParameter(false); + checkParameter(cares.DNS_ORDER_IPV6_FIRST); })().then(common.mustCall()); diff --git a/test/parallel/test-dns.js b/test/parallel/test-dns.js index 40866d4718281a..5b00a3d86c0d3b 100644 --- a/test/parallel/test-dns.js +++ b/test/parallel/test-dns.js @@ -292,7 +292,7 @@ dns.lookup('', { await dnsPromises.lookup('', { hints: dns.ADDRCONFIG | dns.V4MAPPED | dns.ALL }); - await dnsPromises.lookup('', { verbatim: true }); + await dnsPromises.lookup('', { order: 'verbatim' }); })().then(common.mustCall()); {