-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathindex.js
120 lines (97 loc) · 3.1 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
var childProcess = require("child_process");
var portfinder = require('portfinder');
var assert = require("assert");
/**
* Merges values from both obj1 and obj2, overwriting obj1's values and adding obj2's if non existent in obj1
* @param obj1
* @param obj2
* @returns obj3 a new object based on obj1 and obj2
*/
function merge_options(obj1,obj2){
var obj3 = {};
for (var attr in obj1) { obj3[attr] = obj1[attr]; }
for (var attr in obj2) { obj3[attr] = obj2[attr]; }
return obj3;
}
/**
* Connect to the remote SSH host, then open a tunnel to the Target Host.
* After that, executes a given callback and then closes the tunnel.
*/
function tunnelExec(options, callback) {
var defaultOptions = {
user: null,
identityFile: null,
localPort: null,
// Host which is being SSH'd
remoteHost: null,
remotePort: 22,
// Target host, will receive the commands executed through the tunnel
targetHost: null,
targetPort: null,
// Connection timeout
timeout: 15000
};
var params = merge_options(defaultOptions, options);
if(!params.remoteHost){
callback(new Error('Missing remoteHost'));
return false;
}
if(!params.targetPort){
callback(new Error('missing targetPort'));
return false;
}
// If no local port is set, we find one through portfinder
if (!params.localPort) {
return portfinder.getPort(function(err, port) {
params.localPort = port;
tunnelExec(params, cb);
});
}
// Builds remote host string
var connectHost = params.remoteHost;
if(params.user){
connectHost = params.user + "@" + connectHost;
}
// If no target Host, assume is the same as the remoteHost
if(!params.targetHost){
params.targetHost = params.remoteHost;
}
// Sets arguments for the ssh command
var args = [
"-p",
params.remotePort,
connectHost,
"-L",
params.localPort + ":" + params.targetHost + ':' + params.targetPort,
"-N",
"-v"
];
// Adds identityFile if any exists
if(params.identityFile){
args.push('-i');
args.push(params.identityFile);
}
// Force native (english) language, so we can read debug messages correctly
process.env['LANG'] = 'C';
var child = childProcess.spawn("ssh", args);
var timeoutKillProcess = setTimeout(kill, params.timeout);
function kill() {
child.kill('SIGKILL');
callback(new Error('Error establishing SSH connection'));
}
function close() {
child.kill('SIGKILL');
}
// When the process receives data, process it and start callback (if forwarding succeded)
child.stderr.on('data', function bootload(data) {
if (data.toString().match(/local forwarding listening/i)) {
clearTimeout(timeoutKillProcess);
child.stderr.removeListener('data', bootload);
callback(null, {
close: close,
params: params
});
}
});
}
module.exports = tunnelExec;