1'use strict'; 2const { 3 ArrayPrototypeMap, 4 ObjectDefineProperty, 5 Promise, 6 ReflectApply, 7 Symbol, 8} = primordials; 9 10const { 11 bindDefaultResolver, 12 createResolverClass, 13 validateHints, 14 emitInvalidHostnameWarning, 15 getDefaultVerbatim, 16 errorCodes: dnsErrorCodes, 17 getDefaultResultOrder, 18 setDefaultResultOrder, 19 setDefaultResolver, 20} = require('internal/dns/utils'); 21 22const { 23 NODATA, 24 FORMERR, 25 SERVFAIL, 26 NOTFOUND, 27 NOTIMP, 28 REFUSED, 29 BADQUERY, 30 BADNAME, 31 BADFAMILY, 32 BADRESP, 33 CONNREFUSED, 34 TIMEOUT, 35 EOF, 36 FILE, 37 NOMEM, 38 DESTRUCTION, 39 BADSTR, 40 BADFLAGS, 41 NONAME, 42 BADHINTS, 43 NOTINITIALIZED, 44 LOADIPHLPAPI, 45 ADDRGETNETWORKPARAMS, 46 CANCELLED, 47} = dnsErrorCodes; 48const { codes, dnsException } = require('internal/errors'); 49const { toASCII } = require('internal/idna'); 50const { isIP } = require('internal/net'); 51const { 52 getaddrinfo, 53 getnameinfo, 54 GetAddrInfoReqWrap, 55 GetNameInfoReqWrap, 56 QueryReqWrap, 57} = internalBinding('cares_wrap'); 58const { 59 ERR_INVALID_ARG_TYPE, 60 ERR_INVALID_ARG_VALUE, 61 ERR_MISSING_ARGS, 62} = codes; 63const { 64 validateBoolean, 65 validateNumber, 66 validateOneOf, 67 validatePort, 68 validateString, 69} = require('internal/validators'); 70 71const kPerfHooksDnsLookupContext = Symbol('kPerfHooksDnsLookupContext'); 72const kPerfHooksDnsLookupServiceContext = Symbol('kPerfHooksDnsLookupServiceContext'); 73const kPerfHooksDnsLookupResolveContext = Symbol('kPerfHooksDnsLookupResolveContext'); 74 75const { 76 hasObserver, 77 startPerf, 78 stopPerf, 79} = require('internal/perf/observe'); 80 81function onlookup(err, addresses) { 82 if (err) { 83 this.reject(dnsException(err, 'getaddrinfo', this.hostname)); 84 return; 85 } 86 87 const family = this.family || isIP(addresses[0]); 88 this.resolve({ address: addresses[0], family }); 89 if (this[kPerfHooksDnsLookupContext] && hasObserver('dns')) { 90 stopPerf(this, kPerfHooksDnsLookupContext, { detail: { addresses } }); 91 } 92} 93 94function onlookupall(err, addresses) { 95 if (err) { 96 this.reject(dnsException(err, 'getaddrinfo', this.hostname)); 97 return; 98 } 99 100 const family = this.family; 101 102 for (let i = 0; i < addresses.length; i++) { 103 const address = addresses[i]; 104 105 addresses[i] = { 106 address, 107 family: family || isIP(addresses[i]), 108 }; 109 } 110 111 this.resolve(addresses); 112 if (this[kPerfHooksDnsLookupContext] && hasObserver('dns')) { 113 stopPerf(this, kPerfHooksDnsLookupContext, { detail: { addresses } }); 114 } 115} 116 117function createLookupPromise(family, hostname, all, hints, verbatim) { 118 return new Promise((resolve, reject) => { 119 if (!hostname) { 120 emitInvalidHostnameWarning(hostname); 121 resolve(all ? [] : { address: null, family: family === 6 ? 6 : 4 }); 122 return; 123 } 124 125 const matchedFamily = isIP(hostname); 126 127 if (matchedFamily !== 0) { 128 const result = { address: hostname, family: matchedFamily }; 129 resolve(all ? [result] : result); 130 return; 131 } 132 133 const req = new GetAddrInfoReqWrap(); 134 135 req.family = family; 136 req.hostname = hostname; 137 req.oncomplete = all ? onlookupall : onlookup; 138 req.resolve = resolve; 139 req.reject = reject; 140 141 const err = getaddrinfo(req, toASCII(hostname), family, hints, verbatim); 142 143 if (err) { 144 reject(dnsException(err, 'getaddrinfo', hostname)); 145 } else if (hasObserver('dns')) { 146 const detail = { 147 hostname, 148 family, 149 hints, 150 verbatim, 151 }; 152 startPerf(req, kPerfHooksDnsLookupContext, { type: 'dns', name: 'lookup', detail }); 153 } 154 }); 155} 156 157const validFamilies = [0, 4, 6]; 158function lookup(hostname, options) { 159 let hints = 0; 160 let family = 0; 161 let all = false; 162 let verbatim = getDefaultVerbatim(); 163 164 // Parse arguments 165 if (hostname) { 166 validateString(hostname, 'hostname'); 167 } 168 169 if (typeof options === 'number') { 170 validateOneOf(options, 'family', validFamilies); 171 family = options; 172 } else if (options !== undefined && typeof options !== 'object') { 173 throw new ERR_INVALID_ARG_TYPE('options', ['integer', 'object'], options); 174 } else { 175 if (options?.hints != null) { 176 validateNumber(options.hints, 'options.hints'); 177 hints = options.hints >>> 0; 178 validateHints(hints); 179 } 180 if (options?.family != null) { 181 validateOneOf(options.family, 'options.family', validFamilies); 182 family = options.family; 183 } 184 if (options?.all != null) { 185 validateBoolean(options.all, 'options.all'); 186 all = options.all; 187 } 188 if (options?.verbatim != null) { 189 validateBoolean(options.verbatim, 'options.verbatim'); 190 verbatim = options.verbatim; 191 } 192 } 193 194 return createLookupPromise(family, hostname, all, hints, verbatim); 195} 196 197 198function onlookupservice(err, hostname, service) { 199 if (err) { 200 this.reject(dnsException(err, 'getnameinfo', this.host)); 201 return; 202 } 203 204 this.resolve({ hostname, service }); 205 if (this[kPerfHooksDnsLookupServiceContext] && hasObserver('dns')) { 206 stopPerf(this, kPerfHooksDnsLookupServiceContext, { detail: { hostname, service } }); 207 } 208} 209 210function createLookupServicePromise(hostname, port) { 211 return new Promise((resolve, reject) => { 212 const req = new GetNameInfoReqWrap(); 213 214 req.hostname = hostname; 215 req.port = port; 216 req.oncomplete = onlookupservice; 217 req.resolve = resolve; 218 req.reject = reject; 219 220 const err = getnameinfo(req, hostname, port); 221 222 if (err) 223 reject(dnsException(err, 'getnameinfo', hostname)); 224 else if (hasObserver('dns')) { 225 startPerf(req, kPerfHooksDnsLookupServiceContext, { 226 type: 'dns', 227 name: 'lookupService', 228 detail: { 229 host: hostname, 230 port, 231 }, 232 }); 233 } 234 }); 235} 236 237function lookupService(address, port) { 238 if (arguments.length !== 2) 239 throw new ERR_MISSING_ARGS('address', 'port'); 240 241 if (isIP(address) === 0) 242 throw new ERR_INVALID_ARG_VALUE('address', address); 243 244 validatePort(port); 245 246 return createLookupServicePromise(address, +port); 247} 248 249 250function onresolve(err, result, ttls) { 251 if (err) { 252 this.reject(dnsException(err, this.bindingName, this.hostname)); 253 return; 254 } 255 256 if (ttls && this.ttl) 257 result = ArrayPrototypeMap( 258 result, (address, index) => ({ address, ttl: ttls[index] })); 259 260 this.resolve(result); 261 if (this[kPerfHooksDnsLookupResolveContext] && hasObserver('dns')) { 262 stopPerf(this, kPerfHooksDnsLookupResolveContext, { detail: { result } }); 263 } 264} 265 266function createResolverPromise(resolver, bindingName, hostname, ttl) { 267 return new Promise((resolve, reject) => { 268 const req = new QueryReqWrap(); 269 270 req.bindingName = bindingName; 271 req.hostname = hostname; 272 req.oncomplete = onresolve; 273 req.resolve = resolve; 274 req.reject = reject; 275 req.ttl = ttl; 276 277 const err = resolver._handle[bindingName](req, toASCII(hostname)); 278 279 if (err) 280 reject(dnsException(err, bindingName, hostname)); 281 else if (hasObserver('dns')) { 282 startPerf(req, kPerfHooksDnsLookupResolveContext, { 283 type: 'dns', 284 name: bindingName, 285 detail: { 286 host: hostname, 287 ttl, 288 }, 289 }); 290 } 291 }); 292} 293 294function resolver(bindingName) { 295 function query(name, options) { 296 validateString(name, 'name'); 297 298 const ttl = !!(options && options.ttl); 299 return createResolverPromise(this, bindingName, name, ttl); 300 } 301 302 ObjectDefineProperty(query, 'name', { __proto__: null, value: bindingName }); 303 return query; 304} 305 306function resolve(hostname, rrtype) { 307 let resolver; 308 309 if (rrtype !== undefined) { 310 validateString(rrtype, 'rrtype'); 311 312 resolver = resolveMap[rrtype]; 313 314 if (typeof resolver !== 'function') 315 throw new ERR_INVALID_ARG_VALUE('rrtype', rrtype); 316 } else { 317 resolver = resolveMap.A; 318 } 319 320 return ReflectApply(resolver, this, [hostname]); 321} 322 323// Promise-based resolver. 324const { Resolver, resolveMap } = createResolverClass(resolver); 325Resolver.prototype.resolve = resolve; 326 327function defaultResolverSetServers(servers) { 328 const resolver = new Resolver(); 329 330 resolver.setServers(servers); 331 setDefaultResolver(resolver); 332 bindDefaultResolver(module.exports, Resolver.prototype); 333} 334 335module.exports = { 336 lookup, 337 lookupService, 338 Resolver, 339 getDefaultResultOrder, 340 setDefaultResultOrder, 341 setServers: defaultResolverSetServers, 342 343 // ERROR CODES 344 NODATA, 345 FORMERR, 346 SERVFAIL, 347 NOTFOUND, 348 NOTIMP, 349 REFUSED, 350 BADQUERY, 351 BADNAME, 352 BADFAMILY, 353 BADRESP, 354 CONNREFUSED, 355 TIMEOUT, 356 EOF, 357 FILE, 358 NOMEM, 359 DESTRUCTION, 360 BADSTR, 361 BADFLAGS, 362 NONAME, 363 BADHINTS, 364 NOTINITIALIZED, 365 LOADIPHLPAPI, 366 ADDRGETNETWORKPARAMS, 367 CANCELLED, 368}; 369bindDefaultResolver(module.exports, Resolver.prototype); 370