node-gamedig/lib/DnsResolver.js

75 lines
2.2 KiB
JavaScript
Raw Normal View History

import dns from 'node:dns'
import punycode from 'punycode/punycode.js'
export default 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
* @param {number} ipFamily
* @param {string=} srvRecordPrefix
* @returns {Promise<{address:string, port:number=}>}
*/
async resolve (host, ipFamily, srvRecordPrefix) {
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 dns.promises.resolve(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,
...await this.resolve(srvHost, ipFamily, srvRecordPrefix)
}
}
this.logger.debug('No SRV Record')
} catch (e) {
this.logger.debug(e)
}
}
this.logger.debug('Standard Resolve: ' + host)
const dnsResult = await dns.promises.lookup(host, ipFamily)
// 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
}
this.logger.debug('Found address: ' + address)
return { address }
}
}