Skip to content

Commit

Permalink
dns: add order option and support ipv6first
Browse files Browse the repository at this point in the history
PR-URL: #52492
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Marco Ippolito <[email protected]>
  • Loading branch information
ShogunPanda authored and marco-ippolito committed May 3, 2024
1 parent b6cb74d commit 4acca8e
Show file tree
Hide file tree
Showing 21 changed files with 403 additions and 91 deletions.
10 changes: 7 additions & 3 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
66 changes: 53 additions & 13 deletions doc/api/dns.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ section if a custom port is used.
<!-- YAML
added: v0.1.90
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/52492
description: The `verbatim` option is now deprecated in favor of the new `order` option.
- version: v18.4.0
pr-url: https://github.com/nodejs/node/pull/43054
description: For compatibility with `node:net`, when passing an option
Expand Down Expand Up @@ -211,9 +214,18 @@ changes:
flags may be passed by bitwise `OR`ing their values.
* `all` {boolean} When `true`, the callback returns all resolved addresses in
an array. Otherwise, returns a single address. **Default:** `false`.
* `order` {string} When `verbatim`, the resolved addresses are return
unsorted. When `ipv4first`, the resolved addresses are sorted by placing
IPv4 addresses before IPv6 addresses. When `ipv6first`, the resolved
addresses are sorted by placing IPv6 addresses before IPv4 addresses.
**Default:** `verbatim` (addresses are not reordered).
Default value is configurable using [`dns.setDefaultResultOrder()`][] or
[`--dns-result-order`][].
* `verbatim` {boolean} When `true`, the callback receives 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:** `true` (addresses are not reordered). Default value is
configurable using [`dns.setDefaultResultOrder()`][] or
[`--dns-result-order`][].
Expand Down Expand Up @@ -775,18 +787,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 [`dns.setDefaultResultOrder()`][] have higher
priority than [`--dns-result-order`][]. When using [worker threads][],
Expand All @@ -796,14 +812,21 @@ dns orders in workers.
## `dns.getDefaultResultOrder()`

<!-- YAML
added: v20.1.0
added:
- v20.1.0
- v18.17.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/52492
description: The `ipv6first` value is supported now.
-->

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)`

Expand Down Expand Up @@ -947,6 +970,10 @@ section if a custom port is used.

<!-- YAML
added: v10.6.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/52492
description: The `verbatim` option is now deprecated in favor of the new `order` option.
-->

* `hostname` {string}
Expand All @@ -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
Expand Down Expand Up @@ -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][],
Expand Down
26 changes: 21 additions & 5 deletions lib/dns.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ const {
setDefaultResolver,
validateHints,
emitInvalidHostnameWarning,
getDefaultVerbatim,
getDefaultResultOrder,
setDefaultResultOrder,
errorCodes: dnsErrorCodes,
Expand Down Expand Up @@ -89,6 +88,9 @@ const {
const {
GetAddrInfoReqWrap,
GetNameInfoReqWrap,
DNS_ORDER_VERBATIM,
DNS_ORDER_IPV4_FIRST,
DNS_ORDER_IPV6_FIRST,
} = cares;

const kPerfHooksDnsLookupContext = Symbol('kPerfHooksDnsLookupContext');
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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));
Expand All @@ -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;
Expand Down
36 changes: 26 additions & 10 deletions lib/internal/dns/promises.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ const {
createResolverClass,
validateHints,
emitInvalidHostnameWarning,
getDefaultVerbatim,
errorCodes: dnsErrorCodes,
getDefaultResultOrder,
setDefaultResultOrder,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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<DNSLookupResult | DNSLookupResult[]>} 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);
Expand All @@ -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));
Expand All @@ -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 });
}
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
}


Expand Down
8 changes: 2 additions & 6 deletions lib/internal/dns/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -351,7 +348,6 @@ module.exports = {
validateTimeout,
validateTries,
emitInvalidHostnameWarning,
getDefaultVerbatim,
getDefaultResultOrder,
setDefaultResultOrder,
errorCodes,
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/modules/esm/fetch_module.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading

0 comments on commit 4acca8e

Please sign in to comment.