| 'use strict'; |
| |
| const { |
| ArrayIsArray, |
| } = primordials; |
| |
| const errors = require('internal/errors'); |
| const { isIP } = require('internal/net'); |
| const { |
| ChannelWrap, |
| strerror, |
| AI_ADDRCONFIG, |
| AI_V4MAPPED |
| } = internalBinding('cares_wrap'); |
| const IANA_DNS_PORT = 53; |
| const IPv6RE = /^\[([^[\]]*)\]/; |
| const addrSplitRE = /(^.+?)(?::(\d+))?$/; |
| const { |
| ERR_DNS_SET_SERVERS_FAILED, |
| ERR_INVALID_ARG_TYPE, |
| ERR_INVALID_IP_ADDRESS, |
| ERR_INVALID_OPT_VALUE |
| } = errors.codes; |
| |
| // Resolver instances correspond 1:1 to c-ares channels. |
| class Resolver { |
| constructor() { |
| this._handle = new ChannelWrap(); |
| } |
| |
| cancel() { |
| this._handle.cancel(); |
| } |
| |
| getServers() { |
| return this._handle.getServers().map((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) { |
| if (!ArrayIsArray(servers)) { |
| throw new ERR_INVALID_ARG_TYPE('servers', 'Array', 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 = []; |
| |
| servers.forEach((serv, index) => { |
| if (typeof serv !== 'string') { |
| throw new ERR_INVALID_ARG_TYPE(`servers[${index}]`, 'string', serv); |
| } |
| let ipVersion = isIP(serv); |
| |
| if (ipVersion !== 0) |
| return newSet.push([ipVersion, serv, IANA_DNS_PORT]); |
| |
| const match = serv.match(IPv6RE); |
| |
| // Check for an IPv6 in brackets. |
| if (match) { |
| ipVersion = isIP(match[1]); |
| |
| if (ipVersion !== 0) { |
| const port = |
| parseInt(serv.replace(addrSplitRE, '$2')) || IANA_DNS_PORT; |
| return newSet.push([ipVersion, match[1], port]); |
| } |
| } |
| |
| // addr::port |
| const addrSplitMatch = serv.match(addrSplitRE); |
| |
| if (addrSplitMatch) { |
| const hostIP = addrSplitMatch[1]; |
| const port = addrSplitMatch[2] || IANA_DNS_PORT; |
| |
| ipVersion = isIP(hostIP); |
| |
| if (ipVersion !== 0) { |
| return newSet.push([ipVersion, hostIP, parseInt(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(orig.join(',')); |
| const err = strerror(errorNumber); |
| throw new ERR_DNS_SET_SERVERS_FAILED(err, servers); |
| } |
| } |
| } |
| |
| let defaultResolver = new Resolver(); |
| const resolverKeys = [ |
| 'getServers', |
| 'resolve', |
| 'resolve4', |
| 'resolve6', |
| 'resolveAny', |
| 'resolveCname', |
| 'resolveMx', |
| 'resolveNaptr', |
| 'resolveNs', |
| 'resolvePtr', |
| 'resolveSoa', |
| 'resolveSrv', |
| 'resolveTxt', |
| 'reverse', |
| ]; |
| |
| function getDefaultResolver() { |
| return defaultResolver; |
| } |
| |
| function setDefaultResolver(resolver) { |
| defaultResolver = resolver; |
| } |
| |
| function bindDefaultResolver(target, source) { |
| resolverKeys.forEach((key) => { |
| target[key] = source[key].bind(defaultResolver); |
| }); |
| } |
| |
| function validateHints(hints) { |
| if (hints !== 0 && |
| hints !== AI_ADDRCONFIG && |
| hints !== AI_V4MAPPED && |
| hints !== (AI_ADDRCONFIG | AI_V4MAPPED)) { |
| throw new ERR_INVALID_OPT_VALUE('hints', hints); |
| } |
| } |
| |
| let invalidHostnameWarningEmitted = false; |
| |
| function emitInvalidHostnameWarning(hostname) { |
| if (invalidHostnameWarningEmitted) { |
| return; |
| } |
| invalidHostnameWarningEmitted = true; |
| process.emitWarning( |
| `The provided hostname "${hostname}" is not a valid ` + |
| 'hostname, and is supported in the dns module solely for compatibility.', |
| 'DeprecationWarning', |
| 'DEP0118' |
| ); |
| } |
| |
| module.exports = { |
| bindDefaultResolver, |
| getDefaultResolver, |
| setDefaultResolver, |
| validateHints, |
| Resolver, |
| emitInvalidHostnameWarning, |
| }; |