0
0
mirror of https://github.com/nodejs/node.git synced 2024-12-01 16:10:02 +01:00
nodejs/lib/internal/dns/promises.js
Ulises Gascón beb0f03e78 dns: fix inconsistent (hostname vs host)
Fixes: https://github.com/nodejs/node/issues/20892
PR-URL: https://github.com/nodejs/node/pull/23572
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
2018-10-20 21:56:28 -07:00

251 lines
6.4 KiB
JavaScript

'use strict';
const {
bindDefaultResolver,
Resolver: CallbackResolver,
validateHints,
emitInvalidHostnameWarning,
} = require('internal/dns/utils');
const { codes, dnsException } = require('internal/errors');
const { isIP, isIPv4, isLegalPort } = require('internal/net');
const {
getaddrinfo,
getnameinfo,
ChannelWrap,
GetAddrInfoReqWrap,
GetNameInfoReqWrap,
QueryReqWrap
} = internalBinding('cares_wrap');
const {
ERR_INVALID_ARG_TYPE,
ERR_INVALID_OPT_VALUE,
ERR_MISSING_ARGS,
ERR_SOCKET_BAD_PORT
} = codes;
function onlookup(err, addresses) {
if (err) {
this.reject(dnsException(err, 'getaddrinfo', this.hostname));
return;
}
const family = this.family ? this.family : isIPv4(addresses[0]) ? 4 : 6;
this.resolve({ address: addresses[0], family });
}
function onlookupall(err, addresses) {
if (err) {
this.reject(dnsException(err, 'getaddrinfo', this.hostname));
return;
}
const family = this.family;
for (var i = 0; i < addresses.length; i++) {
const address = addresses[i];
addresses[i] = {
address,
family: family ? family : isIPv4(addresses[i]) ? 4 : 6
};
}
this.resolve(addresses);
}
function createLookupPromise(family, hostname, all, hints, verbatim) {
return new Promise((resolve, reject) => {
if (!hostname) {
emitInvalidHostnameWarning(hostname);
if (all)
resolve([]);
else
resolve({ address: null, family: family === 6 ? 6 : 4 });
return;
}
const matchedFamily = isIP(hostname);
if (matchedFamily !== 0) {
const result = { address: hostname, family: matchedFamily };
if (all)
resolve([result]);
else
resolve(result);
return;
}
const req = new GetAddrInfoReqWrap();
req.family = family;
req.hostname = hostname;
req.oncomplete = all ? onlookupall : onlookup;
req.resolve = resolve;
req.reject = reject;
const err = getaddrinfo(req, hostname, family, hints, verbatim);
if (err) {
reject(dnsException(err, 'getaddrinfo', hostname));
}
});
}
function lookup(hostname, options) {
var hints = 0;
var family = -1;
var all = false;
var verbatim = false;
// Parse arguments
if (hostname && typeof hostname !== 'string') {
throw new ERR_INVALID_ARG_TYPE('hostname', 'string', hostname);
} else if (options !== null && typeof options === 'object') {
hints = options.hints >>> 0;
family = options.family >>> 0;
all = options.all === true;
verbatim = options.verbatim === true;
validateHints(hints);
} else {
family = options >>> 0;
}
if (family !== 0 && family !== 4 && family !== 6)
throw new ERR_INVALID_OPT_VALUE('family', family);
return createLookupPromise(family, hostname, all, hints, verbatim);
}
function onlookupservice(err, hostname, service) {
if (err) {
this.reject(dnsException(err, 'getnameinfo', this.host));
return;
}
this.resolve({ hostname, service });
}
function createLookupServicePromise(hostname, port) {
return new Promise((resolve, reject) => {
const req = new GetNameInfoReqWrap();
req.hostname = hostname;
req.port = port;
req.oncomplete = onlookupservice;
req.resolve = resolve;
req.reject = reject;
const err = getnameinfo(req, hostname, port);
if (err)
reject(dnsException(err, 'getnameinfo', hostname));
});
}
function lookupService(hostname, port) {
if (arguments.length !== 2)
throw new ERR_MISSING_ARGS('hostname', 'port');
if (isIP(hostname) === 0)
throw new ERR_INVALID_OPT_VALUE('hostname', hostname);
if (!isLegalPort(port))
throw new ERR_SOCKET_BAD_PORT(port);
return createLookupServicePromise(hostname, +port);
}
function onresolve(err, result, ttls) {
if (err) {
this.reject(dnsException(err, this.bindingName, this.hostname));
return;
}
if (ttls && this.ttl)
result = result.map((address, index) => ({ address, ttl: ttls[index] }));
this.resolve(result);
}
function createResolverPromise(resolver, bindingName, hostname, ttl) {
return new Promise((resolve, reject) => {
const req = new QueryReqWrap();
req.bindingName = bindingName;
req.hostname = hostname;
req.oncomplete = onresolve;
req.resolve = resolve;
req.reject = reject;
req.ttl = ttl;
const err = resolver._handle[bindingName](req, hostname);
if (err)
reject(dnsException(err, bindingName, hostname));
});
}
function resolver(bindingName) {
function query(name, options) {
if (typeof name !== 'string') {
throw new ERR_INVALID_ARG_TYPE('name', 'string', name);
}
const ttl = !!(options && options.ttl);
return createResolverPromise(this, bindingName, name, ttl);
}
Object.defineProperty(query, 'name', { value: bindingName });
return query;
}
const resolveMap = Object.create(null);
// Resolver instances correspond 1:1 to c-ares channels.
class Resolver {
constructor() {
this._handle = new ChannelWrap();
}
}
Resolver.prototype.getServers = CallbackResolver.prototype.getServers;
Resolver.prototype.setServers = CallbackResolver.prototype.setServers;
Resolver.prototype.resolveAny = resolveMap.ANY = resolver('queryAny');
Resolver.prototype.resolve4 = resolveMap.A = resolver('queryA');
Resolver.prototype.resolve6 = resolveMap.AAAA = resolver('queryAaaa');
Resolver.prototype.resolveCname = resolveMap.CNAME = resolver('queryCname');
Resolver.prototype.resolveMx = resolveMap.MX = resolver('queryMx');
Resolver.prototype.resolveNs = resolveMap.NS = resolver('queryNs');
Resolver.prototype.resolveTxt = resolveMap.TXT = resolver('queryTxt');
Resolver.prototype.resolveSrv = resolveMap.SRV = resolver('querySrv');
Resolver.prototype.resolvePtr = resolveMap.PTR = resolver('queryPtr');
Resolver.prototype.resolveNaptr = resolveMap.NAPTR = resolver('queryNaptr');
Resolver.prototype.resolveSoa = resolveMap.SOA = resolver('querySoa');
Resolver.prototype.reverse = resolver('getHostByAddr');
Resolver.prototype.resolve = function resolve(hostname, rrtype) {
var resolver;
if (typeof rrtype === 'string') {
resolver = resolveMap[rrtype];
if (typeof resolver !== 'function')
throw new ERR_INVALID_OPT_VALUE('rrtype', rrtype);
} else if (rrtype === undefined) {
resolver = resolveMap.A;
} else {
throw new ERR_INVALID_ARG_TYPE('rrtype', 'string', rrtype);
}
return resolver.call(this, hostname);
};
module.exports = { lookup, lookupService, Resolver };
bindDefaultResolver(module.exports, Resolver.prototype);