mirror of
https://github.com/nodejs/node.git
synced 2025-05-11 11:17:18 +00:00

PR-URL: https://github.com/nodejs/node/pull/43922 Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
245 lines
5.8 KiB
JavaScript
245 lines
5.8 KiB
JavaScript
'use strict';
|
|
|
|
const {
|
|
ArrayPrototypeForEach,
|
|
ArrayPrototypeJoin,
|
|
ArrayPrototypeMap,
|
|
ArrayPrototypePush,
|
|
FunctionPrototypeBind,
|
|
NumberParseInt,
|
|
RegExpPrototypeExec,
|
|
RegExpPrototypeSymbolReplace,
|
|
} = primordials;
|
|
|
|
const errors = require('internal/errors');
|
|
const { isIP } = require('internal/net');
|
|
const { getOptionValue } = require('internal/options');
|
|
const {
|
|
validateArray,
|
|
validateInt32,
|
|
validateOneOf,
|
|
validateString,
|
|
} = require('internal/validators');
|
|
const {
|
|
ChannelWrap,
|
|
strerror,
|
|
AI_ADDRCONFIG,
|
|
AI_ALL,
|
|
AI_V4MAPPED,
|
|
} = internalBinding('cares_wrap');
|
|
const IANA_DNS_PORT = 53;
|
|
const IPv6RE = /^\[([^[\]]*)\]/;
|
|
const addrSplitRE = /(^.+?)(?::(\d+))?$/;
|
|
const {
|
|
ERR_DNS_SET_SERVERS_FAILED,
|
|
ERR_INVALID_ARG_VALUE,
|
|
ERR_INVALID_IP_ADDRESS,
|
|
} = errors.codes;
|
|
|
|
function validateTimeout(options) {
|
|
const { timeout = -1 } = { ...options };
|
|
validateInt32(timeout, 'options.timeout', -1);
|
|
return timeout;
|
|
}
|
|
|
|
function validateTries(options) {
|
|
const { tries = 4 } = { ...options };
|
|
validateInt32(tries, 'options.tries', 1);
|
|
return tries;
|
|
}
|
|
|
|
// Resolver instances correspond 1:1 to c-ares channels.
|
|
class Resolver {
|
|
constructor(options = undefined) {
|
|
const timeout = validateTimeout(options);
|
|
const tries = validateTries(options);
|
|
this._handle = new ChannelWrap(timeout, tries);
|
|
}
|
|
|
|
cancel() {
|
|
this._handle.cancel();
|
|
}
|
|
|
|
getServers() {
|
|
return ArrayPrototypeMap(this._handle.getServers() || [], (val) => {
|
|
if (!val[1] || val[1] === IANA_DNS_PORT)
|
|
return val[0];
|
|
|
|
const host = isIP(val[0]) === 6 ? `[${val[0]}]` : val[0];
|
|
return `${host}:${val[1]}`;
|
|
});
|
|
}
|
|
|
|
setServers(servers) {
|
|
validateArray(servers, 'servers');
|
|
|
|
// Cache the original servers because in the event of an error while
|
|
// setting the servers, c-ares won't have any servers available for
|
|
// resolution.
|
|
const orig = this._handle.getServers() || [];
|
|
const newSet = [];
|
|
|
|
ArrayPrototypeForEach(servers, (serv, index) => {
|
|
validateString(serv, `servers[${index}]`);
|
|
let ipVersion = isIP(serv);
|
|
|
|
if (ipVersion !== 0)
|
|
return ArrayPrototypePush(newSet, [ipVersion, serv, IANA_DNS_PORT]);
|
|
|
|
const match = RegExpPrototypeExec(IPv6RE, serv);
|
|
|
|
// Check for an IPv6 in brackets.
|
|
if (match) {
|
|
ipVersion = isIP(match[1]);
|
|
|
|
if (ipVersion !== 0) {
|
|
const port = NumberParseInt(
|
|
RegExpPrototypeSymbolReplace(addrSplitRE, serv, '$2')) || IANA_DNS_PORT;
|
|
return ArrayPrototypePush(newSet, [ipVersion, match[1], port]);
|
|
}
|
|
}
|
|
|
|
// addr::port
|
|
const addrSplitMatch = RegExpPrototypeExec(addrSplitRE, serv);
|
|
|
|
if (addrSplitMatch) {
|
|
const hostIP = addrSplitMatch[1];
|
|
const port = addrSplitMatch[2] || IANA_DNS_PORT;
|
|
|
|
ipVersion = isIP(hostIP);
|
|
|
|
if (ipVersion !== 0) {
|
|
return ArrayPrototypePush(
|
|
newSet, [ipVersion, hostIP, NumberParseInt(port)]);
|
|
}
|
|
}
|
|
|
|
throw new ERR_INVALID_IP_ADDRESS(serv);
|
|
});
|
|
|
|
const errorNumber = this._handle.setServers(newSet);
|
|
|
|
if (errorNumber !== 0) {
|
|
// Reset the servers to the old servers, because ares probably unset them.
|
|
this._handle.setServers(ArrayPrototypeJoin(orig, ','));
|
|
const err = strerror(errorNumber);
|
|
throw new ERR_DNS_SET_SERVERS_FAILED(err, servers);
|
|
}
|
|
}
|
|
|
|
setLocalAddress(ipv4, ipv6) {
|
|
validateString(ipv4, 'ipv4');
|
|
|
|
if (ipv6 !== undefined) {
|
|
validateString(ipv6, 'ipv6');
|
|
}
|
|
|
|
this._handle.setLocalAddress(ipv4, ipv6);
|
|
}
|
|
}
|
|
|
|
let defaultResolver = new Resolver();
|
|
const resolverKeys = [
|
|
'getServers',
|
|
'resolve',
|
|
'resolve4',
|
|
'resolve6',
|
|
'resolveAny',
|
|
'resolveCaa',
|
|
'resolveCname',
|
|
'resolveMx',
|
|
'resolveNaptr',
|
|
'resolveNs',
|
|
'resolvePtr',
|
|
'resolveSoa',
|
|
'resolveSrv',
|
|
'resolveTxt',
|
|
'reverse',
|
|
];
|
|
|
|
function getDefaultResolver() {
|
|
return defaultResolver;
|
|
}
|
|
|
|
function setDefaultResolver(resolver) {
|
|
defaultResolver = resolver;
|
|
}
|
|
|
|
function bindDefaultResolver(target, source) {
|
|
ArrayPrototypeForEach(resolverKeys, (key) => {
|
|
target[key] = FunctionPrototypeBind(source[key], defaultResolver);
|
|
});
|
|
}
|
|
|
|
function validateHints(hints) {
|
|
if ((hints & ~(AI_ADDRCONFIG | AI_ALL | AI_V4MAPPED)) !== 0) {
|
|
throw new ERR_INVALID_ARG_VALUE('hints', hints);
|
|
}
|
|
}
|
|
|
|
let invalidHostnameWarningEmitted = false;
|
|
function emitInvalidHostnameWarning(hostname) {
|
|
if (!invalidHostnameWarningEmitted) {
|
|
process.emitWarning(
|
|
`The provided hostname "${hostname}" is not a valid ` +
|
|
'hostname, and is supported in the dns module solely for compatibility.',
|
|
'DeprecationWarning',
|
|
'DEP0118'
|
|
);
|
|
invalidHostnameWarningEmitted = true;
|
|
}
|
|
}
|
|
|
|
let dnsOrder = getOptionValue('--dns-result-order') || 'verbatim';
|
|
|
|
function getDefaultVerbatim() {
|
|
return dnsOrder !== 'ipv4first';
|
|
}
|
|
|
|
function setDefaultResultOrder(value) {
|
|
validateOneOf(value, 'dnsOrder', ['verbatim', 'ipv4first']);
|
|
dnsOrder = value;
|
|
}
|
|
|
|
// ERROR CODES
|
|
const errorCodes = {
|
|
NODATA: 'ENODATA',
|
|
FORMERR: 'EFORMERR',
|
|
SERVFAIL: 'ESERVFAIL',
|
|
NOTFOUND: 'ENOTFOUND',
|
|
NOTIMP: 'ENOTIMP',
|
|
REFUSED: 'EREFUSED',
|
|
BADQUERY: 'EBADQUERY',
|
|
BADNAME: 'EBADNAME',
|
|
BADFAMILY: 'EBADFAMILY',
|
|
BADRESP: 'EBADRESP',
|
|
CONNREFUSED: 'ECONNREFUSED',
|
|
TIMEOUT: 'ETIMEOUT',
|
|
EOF: 'EOF',
|
|
FILE: 'EFILE',
|
|
NOMEM: 'ENOMEM',
|
|
DESTRUCTION: 'EDESTRUCTION',
|
|
BADSTR: 'EBADSTR',
|
|
BADFLAGS: 'EBADFLAGS',
|
|
NONAME: 'ENONAME',
|
|
BADHINTS: 'EBADHINTS',
|
|
NOTINITIALIZED: 'ENOTINITIALIZED',
|
|
LOADIPHLPAPI: 'ELOADIPHLPAPI',
|
|
ADDRGETNETWORKPARAMS: 'EADDRGETNETWORKPARAMS',
|
|
CANCELLED: 'ECANCELLED',
|
|
};
|
|
|
|
module.exports = {
|
|
bindDefaultResolver,
|
|
getDefaultResolver,
|
|
setDefaultResolver,
|
|
validateHints,
|
|
validateTimeout,
|
|
validateTries,
|
|
Resolver,
|
|
emitInvalidHostnameWarning,
|
|
getDefaultVerbatim,
|
|
setDefaultResultOrder,
|
|
errorCodes,
|
|
};
|