diff --git a/bin/server b/bin/server index a6bba9d8..10fd77d0 100755 --- a/bin/server +++ b/bin/server @@ -31,6 +31,10 @@ const argv = optimist default: 10, describe: 'maximum number of tcp sockets each client is allowed to establish at one time (the tunnels)' }) + .options('range', { + default: null, + describe: 'will bind incoming connections only on ports in range xxx:xxxx' + }) .argv; if (argv.help) { @@ -42,6 +46,7 @@ const server = CreateServer({ max_tcp_sockets: argv['max-sockets'], secure: argv.secure, domain: argv.domain, + range: argv.range, }); server.listen(argv.port, argv.address, () => { diff --git a/lib/ClientManager.js b/lib/ClientManager.js index e1a78386..6d97265c 100644 --- a/lib/ClientManager.js +++ b/lib/ClientManager.js @@ -3,6 +3,7 @@ import Debug from 'debug'; import Client from './Client'; import TunnelAgent from './TunnelAgent'; +import PortManager from "./PortManager"; // Manage sets of clients // @@ -13,6 +14,7 @@ class ClientManager { // id -> client instance this.clients = new Map(); + this.portManager = new PortManager({range: this.opt.range||null}) // statistics this.stats = { @@ -39,6 +41,7 @@ class ClientManager { const maxSockets = this.opt.max_tcp_sockets; const agent = new TunnelAgent({ + portManager: this.portManager, clientId: id, maxSockets: 10, }); @@ -79,6 +82,7 @@ class ClientManager { if (!client) { return; } + this.portManager.release(client.agent.port); --this.stats.tunnels; delete this.clients[id]; client.close(); diff --git a/lib/TunnelAgent.js b/lib/TunnelAgent.js index efc2231b..a953d726 100644 --- a/lib/TunnelAgent.js +++ b/lib/TunnelAgent.js @@ -20,6 +20,9 @@ class TunnelAgent extends Agent { // sockets we can hand out via createConnection this.availableSockets = []; + this.port = null; + this.clientId = options.clientId + this.portManager = options.portManager || null; // when a createConnection cannot return a socket, it goes into a queue // once a socket is available it is handed out to the next callback @@ -63,13 +66,14 @@ class TunnelAgent extends Agent { }); return new Promise((resolve) => { - server.listen(() => { - const port = server.address().port; - this.debug('tcp server listening on port: %d', port); + const port = this.portManager ? this.portManager.getNextAvailable(this.options.clientId) : null; + server.listen(port,() => { + this.port = server.address().port + this.debug('tcp server listening on port: %d (%s)', this.port, this.clientId); resolve({ // port for lt client tcp connections - port: port, + port: this.port, }); }); }); @@ -115,6 +119,9 @@ class TunnelAgent extends Agent { socket.once('error', (err) => { // we do not log these errors, sessions can drop from clients for many reasons // these are not actionable errors for our server + if(this.portManager){ + this.portManager.release(this.port); + } socket.destroy(); });