Add punycode support (2.0.6)

This commit is contained in:
mmorrison 2019-01-20 03:45:57 -06:00
parent 5aaff8e1e0
commit 05619469b7
6 changed files with 141 additions and 64 deletions

View file

@ -429,6 +429,9 @@ as well: `--debug`, `--pretty`, `--socketTimeout 5000`, etc.
Changelog
---
### 2.0.6
* Added support for host domains requiring Punycode encoding (special characters)
### 2.0.5
* Added support for Counter-Strike: 2D

71
lib/DnsResolver.js Normal file
View file

@ -0,0 +1,71 @@
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
* @param {string=} srvRecordPrefix
* @returns {Promise<{address:string, port:number=}>}
*/
async resolve(host, 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 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,
...await this.resolve(srvHost, srvRecordPrefix)
};
}
this.logger.debug("No SRV Record");
} catch (e) {
this.logger.debug(e);
}
}
this.logger.debug("Standard Resolve: " + host);
const {address,family} = await dnsLookupAsync(host);
this.logger.debug("Found address: " + address);
return {address: address};
}
}
module.exports = DnsResolver;

40
lib/Logger.js Normal file
View file

@ -0,0 +1,40 @@
const HexUtil = require('./HexUtil');
class Logger {
constructor() {
this.debugEnabled = false;
}
debug(...args) {
if (!this.debugEnabled) return;
this._print(...args);
}
_print(...args) {
try {
const strings = this._convertArgsToStrings(...args);
console.log(...strings);
} catch(e) {
console.log("Error while logging: " + e);
}
}
_convertArgsToStrings(...args) {
const out = [];
for (const arg of args) {
if (arg instanceof Error) {
out.push(arg.stack);
} else if (arg instanceof Buffer) {
out.push("\n" + HexUtil.debugDump(arg) + "\n");
} else if (typeof arg == 'function') {
const result = arg.call(undefined, (...args) => out.push(...this._convertArgsToStrings(...args)));
if (result !== undefined) out.push(...this._convertArgsToStrings(result));
} else {
out.push(arg);
}
}
return out;
}
}
module.exports = Logger;

15
package-lock.json generated
View file

@ -1,6 +1,6 @@
{
"name": "gamedig",
"version": "1.0.49",
"version": "2.0.5",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -449,9 +449,9 @@
"integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw=="
},
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"qs": {
"version": "6.5.2",
@ -503,6 +503,13 @@
"requires": {
"psl": "^1.1.24",
"punycode": "^1.4.1"
},
"dependencies": {
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
}
}
}
}

View file

@ -11,7 +11,7 @@
],
"main": "lib/index.js",
"author": "Michael Morrison",
"version": "2.0.5",
"version": "2.0.6",
"repository": {
"type": "git",
"url": "https://github.com/sonicsnes/node-gamedig.git"
@ -31,6 +31,7 @@
"long": "^2.4.0",
"minimist": "^1.2.0",
"moment": "^2.21.0",
"punycode": "^2.1.1",
"request": "^2.88.0",
"request-promise": "^4.2.2",
"varint": "^4.0.1"

View file

@ -1,13 +1,11 @@
const EventEmitter = require('events').EventEmitter,
dns = require('dns'),
net = require('net'),
Reader = require('../lib/reader'),
HexUtil = require('../lib/HexUtil'),
util = require('util'),
dnsLookupAsync = util.promisify(dns.lookup),
dnsResolveAsync = util.promisify(dns.resolve),
requestAsync = require('request-promise'),
Promises = require('../lib/Promises');
Promises = require('../lib/Promises'),
Logger = require('../lib/Logger'),
DnsResolver = require('../lib/DnsResolver');
class Core extends EventEmitter {
constructor() {
@ -17,6 +15,8 @@ class Core extends EventEmitter {
this.delimiter = '\0';
this.srvRecord = null;
this.abortedPromise = null;
this.logger = new Logger();
this.dnsResolver = new DnsResolver(this.logger);
// Sent to us by QueryRunner
this.options = null;
@ -26,6 +26,10 @@ class Core extends EventEmitter {
}
async runAllAttempts() {
if (this.options.debug) {
this.logger.debugEnabled = true;
}
let result = null;
let lastError = null;
for (let attempt = 1; attempt <= this.options.maxAttempts; attempt++) {
@ -72,7 +76,9 @@ class Core extends EventEmitter {
async runOnce() {
const options = this.options;
if (('host' in options) && !('address' in options)) {
options.address = await this.parseDns(options.host);
const resolved = await this.dnsResolver.resolve(options.host, this.srvRecord);
options.address = resolved.address;
if (resolved.port) options.port = resolved.port;
}
const state = {
@ -108,44 +114,6 @@ class Core extends EventEmitter {
async run(state) {}
/**
* @param {string} host
* @returns {Promise<string>}
*/
async parseDns(host) {
const isIp = (host) => {
return !!host.match(/\d+\.\d+\.\d+\.\d+/);
};
const resolveStandard = async (host) => {
if(isIp(host)) return host;
this.debugLog("Standard DNS Lookup: " + host);
const {address,family} = await dnsLookupAsync(host);
this.debugLog(address);
return address;
};
const resolveSrv = async (srv,host) => {
if(isIp(host)) return host;
this.debugLog("SRV DNS Lookup: " + srv+'.'+host);
let records;
try {
records = await dnsResolveAsync(srv + '.' + host, 'SRV');
this.debugLog(records);
if(records.length >= 1) {
const record = records[0];
this.options.port = record.port;
const srvhost = record.name;
return await resolveStandard(srvhost);
}
} catch(e) {
this.debugLog(e.toString());
}
return await resolveStandard(host);
};
if(this.srvRecord) return await resolveSrv(this.srvRecord, host);
else return await resolveStandard(host);
}
/** Param can be a time in ms, or a promise (which will be timed) */
registerRtt(param) {
if (param.then) {
@ -383,22 +351,9 @@ class Core extends EventEmitter {
}
}
/** @deprecated */
debugLog(...args) {
if (!this.options.debug) return;
try {
if(args[0] instanceof Buffer) {
this.debugLog(HexUtil.debugDump(args[0]));
} else if (typeof args[0] == 'function') {
const result = args[0].call(undefined, this.debugLog.bind(this));
if (result !== undefined) {
this.debugLog(result);
}
} else {
console.log(...args);
}
} catch(e) {
console.log("Error while debug logging: " + e);
}
this.logger.debug(...args);
}
}