136 lines
3.8 KiB
JavaScript
136 lines
3.8 KiB
JavaScript
const dns = require('native-dns');
|
|
const { UDPServer, Request } = dns;
|
|
const Promise = require('bluebird');
|
|
|
|
/**
|
|
* A DNS proxy server that will route requests to instances in the TorPool provided.
|
|
* @extends UDPServer
|
|
*/
|
|
class DNSServer extends UDPServer {
|
|
/**
|
|
* Binds the server to a port and IP Address.
|
|
*
|
|
* @async
|
|
* @param {number} port - The port to bind to.
|
|
* @param {string} [host="::"] - Address to bind to. Will default to :: or 0.0.0.0 if not specified.
|
|
* @returns {Promise}
|
|
*
|
|
*/
|
|
async listen() {
|
|
let args = Array.from(arguments);
|
|
let inner_func = super.serve;
|
|
|
|
if (!args[1])
|
|
args[1] = null;
|
|
|
|
return await new Promise((resolve, reject) => {
|
|
args.push(() => {
|
|
let args = Array.from(arguments);
|
|
resolve.apply(args);
|
|
});
|
|
|
|
try {
|
|
inner_func.apply(this, args);
|
|
} catch (error) {
|
|
reject(error);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Creates an instance of `DNSServer`.
|
|
* @param {TorPool} tor_pool - The pool of instances that will be used for requests.
|
|
* @param {Object} [dns_options] - Options that will be passed to the parent constructor.
|
|
* @param {number} dns_timeout - How long to wait before each outbound DNS request before timing out.
|
|
* @param {Logger} [logger] - Winston logger that will be used for logging. If not specified will disable logging.
|
|
*/
|
|
constructor(tor_pool, dns_options, dns_timeout, logger) {
|
|
/**
|
|
* Handles an incoming DNS request.
|
|
*
|
|
* @function handle_request
|
|
* @param {Request} req - Incoming DNS request.
|
|
* @param {Response} res - Outgoing DNS response.
|
|
* @private
|
|
*/
|
|
const handle_request = (req, res) => {
|
|
let connect = (tor_instance) => {
|
|
for (let question of req.question) {
|
|
let dns_port = (tor_instance.dns_port);
|
|
let outbound_req = Request({
|
|
question,
|
|
server: { address: '127.0.0.1', port: dns_port, type: 'udp' },
|
|
timeout: this.dns_timeout
|
|
});
|
|
|
|
outbound_req.on('message', (err, answer) => {
|
|
if (!err && answer) {
|
|
for (let a of answer.answer){
|
|
res.answer.push(a);
|
|
}
|
|
}
|
|
});
|
|
|
|
outbound_req.on('error', (err) => {
|
|
this.logger.error(`[dns]: an error occured while handling the request: ${err.message}`);
|
|
});
|
|
|
|
|
|
outbound_req.on('end', () => {
|
|
let source = { hostname: req.address.address, port: req.address.port, proto: 'dns' };
|
|
/**
|
|
* Fires when the proxy has made a connection through an instance.
|
|
*
|
|
* @event DNSServer#instance-connection
|
|
* @param {TorProcess} instance - Instance that has been connected to.
|
|
* @param {InstanceConnectionSource} source - Details on the source of the connection.
|
|
*/
|
|
this.emit('instance_connection', tor_instance, source);
|
|
this.logger.verbose(`[dns]: ${source.hostname}:${source.port} → 127.0.0.1:${dns_port}${tor_instance.definition.Name ? ' ('+tor_instance.definition.Name+')' : '' }`);
|
|
res.send();
|
|
});
|
|
|
|
outbound_req.send();
|
|
};
|
|
};
|
|
if (this.tor_pool.instances.length) {
|
|
connect(this.tor_pool.next());
|
|
}
|
|
else {
|
|
this.logger.debug(`[dns]: a connection has been attempted, but no tor instances are live... waiting for an instance to come online`);
|
|
this.tor_pool.once('instance_created', connect);
|
|
}
|
|
};
|
|
|
|
super(dns_options);
|
|
/**
|
|
* Winston logger
|
|
* @type {Logger}
|
|
* @public
|
|
*/
|
|
this.logger = logger || require('./winston_silent_logger');
|
|
|
|
/**
|
|
* The pool of instances that will be used for requests.
|
|
* @type {TorPool}
|
|
* @public
|
|
*/
|
|
this.tor_pool = tor_pool;
|
|
|
|
/**
|
|
* Timeout for each outbound DNS request
|
|
* @type {number}
|
|
* @public
|
|
*/
|
|
this.dns_timeout = dns_timeout;
|
|
|
|
this.on('request', handle_request);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Module that contains the {@link DNSSErver} class.
|
|
* @module tor-router/DNSServer
|
|
* @see DNSServer
|
|
*/
|
|
module.exports = DNSServer; |