Skip to content

Commit 03a677a

Browse files
committed
dns: add experimental c-ares cache and lookup support
Add --experimental-dns-cache-max-ttl to expose c-ares query cache, and --experimental-dns-lookup-cares to route dns.lookup() through ares_getaddrinfo instead of libuv's blocking getaddrinfo. Combined, these flags enable fast cached async DNS for all HTTP/net connections without code changes. Refs: #57641
1 parent f08e2e0 commit 03a677a

File tree

10 files changed

+446
-16
lines changed

10 files changed

+446
-16
lines changed

lib/dns.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,12 @@ const {
4040
} = require('internal/errors');
4141
const {
4242
bindDefaultResolver,
43+
getDefaultResolver,
4344
setDefaultResolver,
4445
validateHints,
4546
getDefaultResultOrder,
4647
setDefaultResultOrder,
48+
getUseCares,
4749
errorCodes: dnsErrorCodes,
4850
validDnsOrders,
4951
validFamilies,
@@ -227,9 +229,13 @@ function lookup(hostname, options, callback) {
227229
order = DNS_ORDER_IPV6_FIRST;
228230
}
229231

230-
const err = cares.getaddrinfo(
231-
req, hostname, family, hints, order,
232-
);
232+
let err;
233+
if (getUseCares()) {
234+
const resolver = getDefaultResolver();
235+
err = resolver._handle.getaddrinfo(req, hostname, family, hints, order);
236+
} else {
237+
err = cares.getaddrinfo(req, hostname, family, hints, order);
238+
}
233239
if (err) {
234240
process.nextTick(callback, new DNSException(err, 'getaddrinfo', hostname));
235241
return {};

lib/internal/dns/promises.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ const {
1010
const {
1111
bindDefaultResolver,
1212
createResolverClass,
13+
getDefaultResolver,
1314
validateHints,
1415
errorCodes: dnsErrorCodes,
1516
getDefaultResultOrder,
1617
setDefaultResultOrder,
1718
setDefaultResolver,
19+
getUseCares,
1820
validDnsOrders,
1921
validFamilies,
2022
} = require('internal/dns/utils');
@@ -163,7 +165,13 @@ function createLookupPromise(family, hostname, all, hints, dnsOrder) {
163165
order = DNS_ORDER_IPV6_FIRST;
164166
}
165167

166-
const err = getaddrinfo(req, hostname, family, hints, order);
168+
let err;
169+
if (getUseCares()) {
170+
const resolver = getDefaultResolver();
171+
err = resolver._handle.getaddrinfo(req, hostname, family, hints, order);
172+
} else {
173+
err = getaddrinfo(req, hostname, family, hints, order);
174+
}
167175

168176
if (err) {
169177
reject(new DNSException(err, 'getaddrinfo', hostname));

lib/internal/dns/utils.js

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const {
2020
} = require('internal/errors');
2121
const { isIP } = require('internal/net');
2222
const { getOptionValue } = require('internal/options');
23+
const { emitExperimentalWarning } = require('internal/util');
2324
const {
2425
validateArray,
2526
validateInt32,
@@ -62,6 +63,12 @@ function validateTries(options) {
6263
return tries;
6364
}
6465

66+
function validateCacheMaxTTL(options) {
67+
const { cacheMaxTTL = defaultCacheMaxTTL } = { ...options };
68+
validateUint32(cacheMaxTTL, 'options.cacheMaxTTL');
69+
return cacheMaxTTL;
70+
}
71+
6572
const kSerializeResolver = Symbol('dns:resolver:serialize');
6673
const kDeserializeResolver = Symbol('dns:resolver:deserialize');
6774
const kSnapshotStates = Symbol('dns:resolver:config');
@@ -75,17 +82,21 @@ class ResolverBase {
7582
const timeout = validateTimeout(options);
7683
const tries = validateTries(options);
7784
const maxTimeout = validateMaxTimeout(options);
85+
const cacheMaxTTL = validateCacheMaxTTL(options);
86+
if (cacheMaxTTL > 0 && options?.cacheMaxTTL !== undefined) {
87+
emitExperimentalWarning('dns.Resolver cacheMaxTTL');
88+
}
7889
// If we are building snapshot, save the states of the resolver along
7990
// the way.
8091
if (isBuildingSnapshot()) {
81-
this[kSnapshotStates] = { timeout, tries, maxTimeout };
92+
this[kSnapshotStates] = { timeout, tries, maxTimeout, cacheMaxTTL };
8293
}
83-
this[kInitializeHandle](timeout, tries, maxTimeout);
94+
this[kInitializeHandle](timeout, tries, maxTimeout, cacheMaxTTL);
8495
}
8596

86-
[kInitializeHandle](timeout, tries, maxTimeout) {
97+
[kInitializeHandle](timeout, tries, maxTimeout, cacheMaxTTL) {
8798
const { ChannelWrap } = lazyBinding();
88-
this._handle = new ChannelWrap(timeout, tries, maxTimeout);
99+
this._handle = new ChannelWrap(timeout, tries, maxTimeout, cacheMaxTTL);
89100
}
90101

91102
cancel() {
@@ -195,8 +206,8 @@ class ResolverBase {
195206
}
196207

197208
[kDeserializeResolver]() {
198-
const { timeout, tries, maxTimeout, localAddress, servers } = this[kSnapshotStates];
199-
this[kInitializeHandle](timeout, tries, maxTimeout);
209+
const { timeout, tries, maxTimeout, cacheMaxTTL, localAddress, servers } = this[kSnapshotStates];
210+
this[kInitializeHandle](timeout, tries, maxTimeout, cacheMaxTTL);
200211
if (localAddress) {
201212
const { ipv4, ipv6 } = localAddress;
202213
this._handle.setLocalAddress(ipv4, ipv6);
@@ -209,6 +220,8 @@ class ResolverBase {
209220

210221
let defaultResolver;
211222
let dnsOrder;
223+
let defaultCacheMaxTTL = 0;
224+
let useCares = false;
212225
const validDnsOrders = ['verbatim', 'ipv4first', 'ipv6first'];
213226
const validFamilies = [0, 4, 6];
214227

@@ -222,6 +235,17 @@ function initializeDns() {
222235
dnsOrder = orderFromCLI;
223236
}
224237

238+
const cacheMaxTTLFromCLI = getOptionValue('--experimental-dns-cache-max-ttl');
239+
if (cacheMaxTTLFromCLI > 0) {
240+
emitExperimentalWarning('--experimental-dns-cache-max-ttl');
241+
defaultCacheMaxTTL = cacheMaxTTLFromCLI;
242+
}
243+
244+
if (getOptionValue('--experimental-dns-lookup-cares')) {
245+
emitExperimentalWarning('--experimental-dns-lookup-cares');
246+
useCares = true;
247+
}
248+
225249
if (!isBuildingSnapshot()) {
226250
return;
227251
}
@@ -340,6 +364,10 @@ const errorCodes = {
340364
CANCELLED: 'ECANCELLED',
341365
};
342366

367+
function getUseCares() {
368+
return useCares;
369+
}
370+
343371
module.exports = {
344372
bindDefaultResolver,
345373
getDefaultResolver,
@@ -349,6 +377,7 @@ module.exports = {
349377
validateTries,
350378
getDefaultResultOrder,
351379
setDefaultResultOrder,
380+
getUseCares,
352381
errorCodes,
353382
createResolverClass,
354383
initializeDns,

0 commit comments

Comments
 (0)