2019-01-20 10:45:57 +01:00
|
|
|
const dns = require('dns'),
|
|
|
|
Logger = require('./Logger'),
|
|
|
|
util = require('util'),
|
|
|
|
dnsLookupAsync = util.promisify(dns.lookup),
|
|
|
|
dnsResolveAsync = util.promisify(dns.resolve),
|
|
|
|
punycode = require('punycode');
|
|
|
|
|
|
|
|
class DnsResolver {
|
|
|
|
/**
|
|
|
|
* @param {Logger} logger
|
|
|
|
*/
|
|
|
|
constructor(logger) {
|
|
|
|
this.logger = logger;
|
|
|
|
}
|
|
|
|
|
|
|
|
isIp(host) {
|
|
|
|
return !!host.match(/\d+\.\d+\.\d+\.\d+/);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Response port will only be present if srv record was involved.
|
|
|
|
* @param {string} host
|
2022-12-13 10:46:43 +01:00
|
|
|
* @param {number} ipFamily
|
2019-01-20 10:45:57 +01:00
|
|
|
* @param {string=} srvRecordPrefix
|
|
|
|
* @returns {Promise<{address:string, port:number=}>}
|
|
|
|
*/
|
2022-12-13 10:46:43 +01:00
|
|
|
async resolve(host, ipFamily, srvRecordPrefix) {
|
2019-01-20 10:45:57 +01:00
|
|
|
this.logger.debug("DNS Lookup: " + host);
|
|
|
|
|
|
|
|
if(this.isIp(host)) {
|
|
|
|
this.logger.debug("Raw IP Address: " + host);
|
|
|
|
return {address: host};
|
|
|
|
}
|
|
|
|
|
|
|
|
const asciiForm = punycode.toASCII(host);
|
|
|
|
if (asciiForm !== host) {
|
|
|
|
this.logger.debug("Encoded punycode: " + host + " -> " + asciiForm);
|
|
|
|
host = asciiForm;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (srvRecordPrefix) {
|
|
|
|
this.logger.debug("SRV Resolve: " + srvRecordPrefix + '.' + host);
|
|
|
|
let records;
|
|
|
|
try {
|
|
|
|
records = await dnsResolveAsync(srvRecordPrefix + '.' + host, 'SRV');
|
|
|
|
if (records.length >= 1) {
|
|
|
|
this.logger.debug("Found SRV Records: ", records);
|
|
|
|
const record = records[0];
|
|
|
|
const srvPort = record.port;
|
|
|
|
const srvHost = record.name;
|
|
|
|
if (srvHost === host) {
|
|
|
|
throw new Error('Loop in DNS SRV records');
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
port: srvPort,
|
2022-12-13 10:46:43 +01:00
|
|
|
...await this.resolve(srvHost, ipFamily, srvRecordPrefix)
|
2019-01-20 10:45:57 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
this.logger.debug("No SRV Record");
|
|
|
|
} catch (e) {
|
|
|
|
this.logger.debug(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.logger.debug("Standard Resolve: " + host);
|
2022-12-13 10:46:43 +01:00
|
|
|
const dnsResult = await dnsLookupAsync(host, ipFamily);
|
2019-10-15 21:32:28 +02:00
|
|
|
// For some reason, this sometimes returns a string address rather than an object.
|
|
|
|
// I haven't been able to reproduce, but it's been reported on the issue tracker.
|
|
|
|
let address;
|
|
|
|
if (typeof dnsResult === 'string') {
|
|
|
|
address = dnsResult;
|
|
|
|
} else {
|
|
|
|
address = dnsResult.address;
|
|
|
|
}
|
2019-01-20 10:45:57 +01:00
|
|
|
this.logger.debug("Found address: " + address);
|
|
|
|
return {address: address};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = DnsResolver;
|