1 | var net = require('net');
|
2 | var debug = require('debug')('tunnel-ssh');
|
3 | var Connection = require('ssh2');
|
4 | var createConfig = require('./lib/config');
|
5 | var events = require('events');
|
6 | var noop = function () {
|
7 | };
|
8 |
|
9 | function bindSSHConnection(config, netConnection) {
|
10 | var sshConnection = new Connection();
|
11 |
|
12 | sshConnection.on('ready', function () {
|
13 | debug('sshConnection:ready');
|
14 | netConnection.emit('sshConnection', sshConnection, netConnection);
|
15 | sshConnection.forwardOut(config.srcHost, config.srcPort, config.dstHost, config.dstPort, function (err, sshStream) {
|
16 | if (err) {
|
17 |
|
18 | netConnection.emit('error', err);
|
19 | debug('Destination port:', err);
|
20 | return;
|
21 | }
|
22 |
|
23 | debug('sshStream:create');
|
24 | netConnection.emit('sshStream', sshStream);
|
25 | netConnection.pipe(sshStream).pipe(netConnection);
|
26 | });
|
27 | });
|
28 | return sshConnection;
|
29 | }
|
30 |
|
31 | function createServer(config) {
|
32 | var server;
|
33 | var sshConnection;
|
34 | var connections = [];
|
35 | var connectionCount = 0;
|
36 |
|
37 | server = net.createServer(function (netConnection) {
|
38 | connectionCount++;
|
39 | netConnection.on('error', server.emit.bind(server, 'error'));
|
40 | netConnection.on('close', function () {
|
41 | connectionCount--;
|
42 | if (connectionCount === 0) {
|
43 | if (!config.keepAlive) {
|
44 | setTimeout(function () {
|
45 | if (connectionCount === 0) {
|
46 | server.close();
|
47 | }
|
48 | }, 2);
|
49 | }
|
50 | }
|
51 | });
|
52 |
|
53 | server.emit('netConnection', netConnection, server);
|
54 | sshConnection = bindSSHConnection(config, netConnection);
|
55 | sshConnection.on('error', server.emit.bind(server, 'error'));
|
56 |
|
57 | netConnection.on('sshStream', function (sshStream) {
|
58 | sshStream.on('error', function () {
|
59 | server.close();
|
60 | });
|
61 | });
|
62 |
|
63 | connections.push(sshConnection, netConnection);
|
64 | sshConnection.connect(config);
|
65 | });
|
66 |
|
67 | server.on('close', function () {
|
68 | connections.forEach(function (connection) {
|
69 | connection.end();
|
70 | });
|
71 | });
|
72 |
|
73 | return server;
|
74 | }
|
75 |
|
76 | function tunnel(configArgs, callback) {
|
77 | var server;
|
78 | var config;
|
79 |
|
80 | if (!callback) {
|
81 | callback = noop;
|
82 | }
|
83 | try {
|
84 | config = createConfig(configArgs);
|
85 | server = createServer(config);
|
86 |
|
87 | server.listen(config.localPort, config.localHost, function (error) {
|
88 | callback(error, server);
|
89 | });
|
90 | } catch (e) {
|
91 | server = new events.EventEmitter();
|
92 | setImmediate(function () {
|
93 | callback(e);
|
94 | server.emit('error', e);
|
95 | });
|
96 | }
|
97 | return server;
|
98 | }
|
99 |
|
100 | module.exports = tunnel;
|