bdy 1.7.46-dev

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/.eslintrc.yml +23 -0
  2. package/LICENSE +21 -0
  3. package/bin/cli.js +5 -0
  4. package/dockerfile +15 -0
  5. package/link.sh +3 -0
  6. package/package.json +39 -0
  7. package/src/agent/linux.js +127 -0
  8. package/src/agent/manager.js +404 -0
  9. package/src/agent/osx.js +150 -0
  10. package/src/agent/socket/tunnel.js +232 -0
  11. package/src/agent/socket.js +260 -0
  12. package/src/agent/system.js +205 -0
  13. package/src/agent/wait.js +20 -0
  14. package/src/agent/windows.js +168 -0
  15. package/src/agent.js +248 -0
  16. package/src/api/agent.js +95 -0
  17. package/src/api/buddy.js +131 -0
  18. package/src/api/socket.js +142 -0
  19. package/src/cfg.js +228 -0
  20. package/src/command/agent/disable.js +37 -0
  21. package/src/command/agent/enable.js +117 -0
  22. package/src/command/agent/restart.js +28 -0
  23. package/src/command/agent/run.js +16 -0
  24. package/src/command/agent/start.js +28 -0
  25. package/src/command/agent/status.js +45 -0
  26. package/src/command/agent/stop.js +28 -0
  27. package/src/command/agent/tunnel/http.js +47 -0
  28. package/src/command/agent/tunnel/list.js +27 -0
  29. package/src/command/agent/tunnel/start.js +38 -0
  30. package/src/command/agent/tunnel/status.js +32 -0
  31. package/src/command/agent/tunnel/stop.js +30 -0
  32. package/src/command/agent/tunnel/tcp.js +47 -0
  33. package/src/command/agent/tunnel/tls.js +47 -0
  34. package/src/command/agent/tunnel.js +21 -0
  35. package/src/command/agent/update.js +43 -0
  36. package/src/command/agent/version.js +23 -0
  37. package/src/command/agent.js +27 -0
  38. package/src/command/config/add/http.js +33 -0
  39. package/src/command/config/add/tcp.js +33 -0
  40. package/src/command/config/add/tls.js +33 -0
  41. package/src/command/config/add.js +13 -0
  42. package/src/command/config/get/region.js +13 -0
  43. package/src/command/config/get/timeout.js +13 -0
  44. package/src/command/config/get/token.js +13 -0
  45. package/src/command/config/get/tunnel.js +21 -0
  46. package/src/command/config/get/tunnels.js +13 -0
  47. package/src/command/config/get/whitelist.js +13 -0
  48. package/src/command/config/get.js +19 -0
  49. package/src/command/config/remove/tunnel.js +22 -0
  50. package/src/command/config/remove.js +9 -0
  51. package/src/command/config/set/region.js +19 -0
  52. package/src/command/config/set/timeout.js +22 -0
  53. package/src/command/config/set/token.js +18 -0
  54. package/src/command/config/set/whitelist.js +19 -0
  55. package/src/command/config/set.js +15 -0
  56. package/src/command/config.js +15 -0
  57. package/src/command/http.js +34 -0
  58. package/src/command/pre.js +47 -0
  59. package/src/command/start.js +31 -0
  60. package/src/command/tcp.js +32 -0
  61. package/src/command/tls.js +32 -0
  62. package/src/command/version.js +10 -0
  63. package/src/format.js +171 -0
  64. package/src/index.js +32 -0
  65. package/src/input.js +283 -0
  66. package/src/logger.js +87 -0
  67. package/src/output/interactive/tunnel.js +871 -0
  68. package/src/output/noninteractive/agent/tunnels.js +32 -0
  69. package/src/output/noninteractive/config/tunnel.js +52 -0
  70. package/src/output/noninteractive/config/tunnels.js +19 -0
  71. package/src/output/noninteractive/tunnel.js +79 -0
  72. package/src/output.js +136 -0
  73. package/src/server/cert.js +51 -0
  74. package/src/server/http1.js +79 -0
  75. package/src/server/http2.js +79 -0
  76. package/src/server/sftp.js +474 -0
  77. package/src/server/ssh.js +107 -0
  78. package/src/server/tls.js +41 -0
  79. package/src/ssh/client.js +196 -0
  80. package/src/texts.js +447 -0
  81. package/src/tunnel/agent.js +100 -0
  82. package/src/tunnel/compression.js +32 -0
  83. package/src/tunnel/dns.js +55 -0
  84. package/src/tunnel/html/404.html +129 -0
  85. package/src/tunnel/html/503.html +136 -0
  86. package/src/tunnel/html.js +32 -0
  87. package/src/tunnel/http/log.js +204 -0
  88. package/src/tunnel/http/serve.js +127 -0
  89. package/src/tunnel/http/stream.js +46 -0
  90. package/src/tunnel/http.js +406 -0
  91. package/src/tunnel/identification.js +95 -0
  92. package/src/tunnel/latency.js +63 -0
  93. package/src/tunnel/tcp.js +71 -0
  94. package/src/tunnel.js +696 -0
  95. package/src/utils.js +496 -0
  96. package/unlink.sh +3 -0
package/src/tunnel.js ADDED
@@ -0,0 +1,696 @@
1
+ const basicAuth = require('basic-auth');
2
+ const {
3
+ DEFAULT_TIMEOUT,
4
+ isStringRegExp,
5
+ TARGET_HTTP_REGEX,
6
+ TARGET_ONLY_PORT_REGEX,
7
+ TARGET_TCP_TLS_REGEX,
8
+ TLS_TERMINATE_AT_AGENT,
9
+ TLS_TERMINATE_AT_REGION,
10
+ TLS_TERMINATE_AT_TARGET,
11
+ TUNNEL_CLOSED,
12
+ TUNNEL_HTTP,
13
+ TUNNEL_OPEN,
14
+ TUNNEL_TCP,
15
+ TUNNEL_TLS
16
+ } = require('./utils.js');
17
+ const TunnelLatency = require('./tunnel/latency.js');
18
+ const SshClient = require('./ssh/client.js');
19
+ const EventEmitter = require('events');
20
+ const TunnelTcp = require('./tunnel/tcp.js');
21
+ const ServerTls = require('./server/tls.js');
22
+ const ServerSsh = require('./server/ssh.js');
23
+ const logger = require('./logger.js');
24
+ const TunnelIdentification = require('./tunnel/identification.js');
25
+ const TunnelHttp = require('./tunnel/http.js');
26
+ const ServerHttp2 = require('./server/http2.js');
27
+ const ServerHttp1 = require('./server/http1.js');
28
+ const TunnelHttpLog = require('./tunnel/http/log.js');
29
+ const Format = require('./format');
30
+ const {
31
+ LOG_STARTING_TUNNEL,
32
+ LOG_STOPPING_TUNNEL,
33
+ LOG_TUNNEL_CONNECTED,
34
+ LOG_TUNNEL_DISCONNECTED,
35
+ LOG_TUNNEL_FAILED,
36
+ LOG_TUNNEL_HTTP1_STREAM,
37
+ LOG_TUNNEL_HTTP2_STREAM,
38
+ LOG_TUNNEL_HTTP_CIRCUIT_BREAKER_OPEN,
39
+ LOG_TUNNEL_HTTP_RATE_LIMIT,
40
+ LOG_TUNNEL_HTTP_WRON_AUTH,
41
+ LOG_TUNNEL_HTTP_WRONG_USER_AGENTS,
42
+ LOG_TUNNEL_IDENTIFIED,
43
+ LOG_TUNNEL_TCP_STREAM,
44
+ LOG_TUNNEL_TLS_AGENT_STREAM,
45
+ LOG_TUNNEL_TLS_REGION_STREAM,
46
+ LOG_TUNNEL_TLS_TARGET_STREAM
47
+ } = require('./texts.js');
48
+ const TunnelDns = require('./tunnel/dns.js');
49
+ const {
50
+ EVENT_TUNNEL_IDENTIFIED,
51
+ HTTP1_SOCKET_OPEN,
52
+ HTTP1_SOCKET_CLOSED,
53
+ HTTP1_REQUEST,
54
+ HTTP2_SESSION_OPEN,
55
+ HTTP2_SESSION_CLOSED,
56
+ HTTP2_REQUEST,
57
+ TLS_SOCKET,
58
+ SSH_CLIENT_EVENT_CONNECTED,
59
+ SSH_CLIENT_EVENT_DISCONNECTED,
60
+ SSH_CLIENT_EVENT_STREAM_TCP,
61
+ SSH_CLIENT_EVENT_STREAM_TLS,
62
+ SSH_CLIENT_EVENT_STREAM_HTTP1,
63
+ SSH_CLIENT_EVENT_STREAM_HTTP2,
64
+ EVENT_TUNNEL_HTTP_NEW_RESPONSE,
65
+ EVENT_TUNNEL_HTTP_NEW_REQUEST,
66
+ TUNNEL_LATENCY_EVENT_RECONNECTED,
67
+ TCP_EVENT_CLOSED,
68
+ TUNNEL_EVENT_OPEN,
69
+ TUNNEL_EVENT_CLOSED,
70
+ TUNNEL_EVENT_TCP_OPEN,
71
+ TUNNEL_EVENT_TCP_CLOSED,
72
+ TUNNEL_EVENT_TLS_OPEN,
73
+ TUNNEL_EVENT_TLS_CLOSED,
74
+ TUNNEL_EVENT_HTTP_IDENTIFIED,
75
+ TUNNEL_EVENT_HTTP_REQUEST,
76
+ TUNNEL_EVENT_HTTP_RESPONSE,
77
+ TUNNEL_EVENT_STOPPED,
78
+ TUNNEL_SSH,
79
+ SSH_CLIENT_EVENT_STREAM_SSH,
80
+ createSshHostKey,
81
+ TUNNEL_EVENT_HTTP_OPEN,
82
+ TUNNEL_EVENT_HTTP_CLOSED
83
+ } = require('./utils');
84
+ const { LOG_TUNNEL_SSH_STREAM } = require('./texts');
85
+
86
+ class Tunnel extends EventEmitter {
87
+ constructor({
88
+ id,
89
+ type,
90
+ target,
91
+ region,
92
+ timeout,
93
+ domain,
94
+ subdomain,
95
+ whitelist,
96
+ tlsSettings,
97
+ httpSettings,
98
+ sshSettings,
99
+ sshHostKey
100
+ }) {
101
+ super();
102
+ if (!sshHostKey) sshHostKey = createSshHostKey();
103
+ this.id = id;
104
+ this.sshHostKey = sshHostKey;
105
+ this.create({
106
+ type,
107
+ target,
108
+ region,
109
+ timeout,
110
+ domain,
111
+ subdomain,
112
+ whitelist,
113
+ tlsSettings,
114
+ httpSettings,
115
+ sshSettings,
116
+ });
117
+ }
118
+
119
+ create({
120
+ type,
121
+ target,
122
+ region,
123
+ timeout,
124
+ domain,
125
+ subdomain,
126
+ whitelist,
127
+ tlsSettings,
128
+ httpSettings,
129
+ sshSettings,
130
+ }) {
131
+ this.type = type;
132
+ this.region = region;
133
+ this.target = target;
134
+ this.whitelist = whitelist || [];
135
+ this.domain = domain;
136
+ this.subdomain = subdomain;
137
+ this.timeout = timeout || DEFAULT_TIMEOUT;
138
+ this.useragents = [];
139
+ this.headers = [];
140
+ this.responseHeaders = [];
141
+ if (tlsSettings) {
142
+ this.terminate = tlsSettings.terminate;
143
+ this.key = tlsSettings.key;
144
+ this.cert = tlsSettings.cert;
145
+ this.ca = tlsSettings.ca;
146
+ }
147
+ if (httpSettings) {
148
+ this.host = httpSettings.host;
149
+ this.login = httpSettings.login;
150
+ this.password = httpSettings.password;
151
+ this.ca = httpSettings.ca;
152
+ this.serve = httpSettings.serve;
153
+ this.useragents = httpSettings.userAgents || [];
154
+ this.headers = httpSettings.headers || [];
155
+ this.responseHeaders = httpSettings.responseHeaders || [];
156
+ this.circuitBreaker = httpSettings.circuitBreaker;
157
+ this.log = httpSettings.log;
158
+ this.verify = httpSettings.verify;
159
+ this.compression = httpSettings.compression;
160
+ this.http2 = httpSettings.http2;
161
+ }
162
+ if (sshSettings) {
163
+ this.sshIp = sshSettings.ip;
164
+ this.sshId = sshSettings.sshId;
165
+ this.sshPort = sshSettings.port;
166
+ this.sshUser = sshSettings.user;
167
+ this.sshPassword = sshSettings.password;
168
+ this.sshForwardPort = sshSettings.forwardPort;
169
+ this.sshClientUser = sshSettings.clientUser;
170
+ this.sshClientPassword = sshSettings.clientPassword;
171
+ }
172
+ this.targetProto = 'http';
173
+ this.targetHost = 'localhost';
174
+ this.targetPort = 80;
175
+ this.targetAuth = null;
176
+
177
+ if (this.type === TUNNEL_HTTP) {
178
+ let m = this.target.match(TARGET_ONLY_PORT_REGEX);
179
+ if (m) {
180
+ this.targetPort = parseInt(m[0], 10);
181
+ } else {
182
+ m = this.target.match(TARGET_HTTP_REGEX);
183
+ if (m) {
184
+ if (m[2]) this.targetProto = m[2];
185
+ if (m[6]) this.targetPort = parseInt(m[6], 10);
186
+ else if (this.targetProto === 'https') this.targetPort = 443;
187
+ if (m[4]) this.targetHost = m[4];
188
+ if (m[3]) this.targetAuth = m[3].replace(/@$/, '');
189
+ }
190
+ }
191
+ } else if (this.type === TUNNEL_SSH) {
192
+ this.targetHost = 'localhost';
193
+ this.targetProto = 'ssh://';
194
+ this.targetPort = 22;
195
+ } else {
196
+ const m = this.target.match(TARGET_TCP_TLS_REGEX);
197
+ if (m) {
198
+ this.targetPort = parseInt(m[3], 10);
199
+ if (m[2]) this.targetHost = m[2];
200
+ }
201
+ }
202
+ this.connections = {};
203
+ this.totalConnections = 0;
204
+ this.status = TUNNEL_CLOSED;
205
+ this.dns = null;
206
+ this.regionLatency = null;
207
+ this.targetLatency = null;
208
+ this.tls = null;
209
+ this.httpLog = null;
210
+ this.identify = null;
211
+ this.http2server = null;
212
+ this.http1server = null;
213
+ this.sshServer = null;
214
+ this.ssh = null;
215
+ this.started = false;
216
+ }
217
+
218
+ recreate({
219
+ type,
220
+ target,
221
+ region,
222
+ timeout,
223
+ domain,
224
+ subdomain,
225
+ whitelist,
226
+ tlsSettings,
227
+ httpSettings,
228
+ sshSettings,
229
+ }) {
230
+ const started = this.started;
231
+ this.stop(false);
232
+ this.create({
233
+ type,
234
+ target,
235
+ region,
236
+ timeout,
237
+ domain,
238
+ subdomain,
239
+ whitelist,
240
+ tlsSettings,
241
+ httpSettings,
242
+ sshSettings,
243
+ });
244
+ if (started) this.start();
245
+ }
246
+
247
+ hasChanged(data) {
248
+ const tunnel = new Tunnel({
249
+ ...data,
250
+ sshHostKey: this.sshHostKey
251
+ });
252
+ if (this.type !== tunnel.type) return true;
253
+ if (this.target !== tunnel.target) return true;
254
+ if (this.region !== tunnel.region) return true;
255
+ if (this.timeout !== tunnel.timeout) return true;
256
+ if (this.domain !== tunnel.domain) return true;
257
+ if (this.subdomain !== tunnel.subdomain) return true;
258
+ if (this.terminate !== tunnel.terminate) return true;
259
+ if (this.key !== tunnel.key) return true;
260
+ if (this.cert !== tunnel.cert) return true;
261
+ if (this.ca !== tunnel.ca) return true;
262
+ if (this.host !== tunnel.host) return true;
263
+ if (this.login !== tunnel.login) return true;
264
+ if (this.password !== tunnel.password) return true;
265
+ if (this.serve !== tunnel.serve) return true;
266
+ if (this.circuitBreaker !== tunnel.circuitBreaker) return true;
267
+ if (this.log !== tunnel.log) return true;
268
+ if (this.verify !== tunnel.verify) return true;
269
+ if (this.http2 !== tunnel.http2) return true;
270
+ if (this.compression !== tunnel.compression) return true;
271
+ if (this.sshIp !== tunnel.sshIp) return true;
272
+ if (this.sshId !== tunnel.sshId) return true;
273
+ if (this.sshPort !== tunnel.sshPort) return true;
274
+ if (this.sshUser !== tunnel.sshUser) return true;
275
+ if (this.sshPassword !== tunnel.sshPassword) return true;
276
+ if (this.sshForwardPort !== tunnel.sshForwardPort) return true;
277
+ if (this.sshClientPassword !== tunnel.sshClientPassword) return true;
278
+ if (this.sshClientUser !== tunnel.sshClientUser) return true;
279
+ if (this.whitelist.length !== tunnel.whitelist.length) return true;
280
+ this.whitelist.sort();
281
+ tunnel.whitelist.sort();
282
+ for (let i = 0; i < this.whitelist.length; i += 1) {
283
+ if (this.whitelist[i] !== tunnel.whitelist[i]) return true;
284
+ }
285
+ if (this.useragents.length !== tunnel.useragents.length) return true;
286
+ this.useragents.sort();
287
+ tunnel.useragents.sort();
288
+ for (let i = 0; i < this.useragents.length; i += 1) {
289
+ if (this.useragents[i] !== tunnel.useragents[i]) return true;
290
+ }
291
+ const sortHeaders = (a, b) => a.name.localeCompare(b.name);
292
+ if (this.headers.length !== tunnel.headers.length) return true;
293
+ this.headers.sort(sortHeaders);
294
+ tunnel.headers.sort(sortHeaders);
295
+ for (let i = 0; i < this.headers.length; i += 1) {
296
+ const thisH = this.headers[i];
297
+ const tunnelH = tunnel.headers[i];
298
+ if (thisH.name !== tunnelH.name) return true;
299
+ if (thisH.value !== tunnelH.value) return true;
300
+ }
301
+ if (this.responseHeaders.length !== tunnel.responseHeaders.length) return true;
302
+ this.responseHeaders.sort(sortHeaders);
303
+ tunnel.responseHeaders.sort(sortHeaders);
304
+ for (let i = 0; i < this.responseHeaders.length; i += 1) {
305
+ const thisRH = this.responseHeaders[i];
306
+ const tunnelRH = tunnel.responseHeaders[i];
307
+ if (thisRH.name !== tunnelRH.name) return true;
308
+ if (thisRH.value !== tunnelRH.value) return true;
309
+ }
310
+ return false;
311
+ }
312
+
313
+ async sshConnected() {
314
+ try {
315
+ logger.debug(LOG_TUNNEL_CONNECTED(this.id, this.sshForwardPort));
316
+ await this.ssh.forwardIn(this.sshForwardPort);
317
+ this.status = TUNNEL_OPEN;
318
+ } catch (err) {
319
+ // reconnect
320
+ logger.debug(LOG_TUNNEL_FAILED(this.id));
321
+ logger.debug(err);
322
+ this.ssh.close();
323
+ return;
324
+ }
325
+ this.emit(TUNNEL_EVENT_OPEN, this);
326
+ }
327
+
328
+ sshDisconnected() {
329
+ if (this.status !== TUNNEL_CLOSED) {
330
+ logger.debug(LOG_TUNNEL_DISCONNECTED(this.id));
331
+ this.status = TUNNEL_CLOSED;
332
+ this.emit(TUNNEL_EVENT_CLOSED, this);
333
+ }
334
+ }
335
+
336
+ tunnelToTarget(stream, onClose) {
337
+ this.totalConnections += 1;
338
+ const tcp = new TunnelTcp(this.targetHost, this.targetPort, stream);
339
+ this.connections[tcp.id] = tcp;
340
+ tcp.on(TCP_EVENT_CLOSED, () => {
341
+ this.connections[tcp.id].removeAllListeners();
342
+ delete this.connections[tcp.id];
343
+ onClose();
344
+ });
345
+ tcp.pipe();
346
+ }
347
+
348
+ httpIdentified(type) {
349
+ logger.info(LOG_TUNNEL_IDENTIFIED(this.id, type));
350
+ this.emit(TUNNEL_EVENT_HTTP_IDENTIFIED, this, type);
351
+ }
352
+
353
+ httpConnectionOpen(s) {
354
+ this.totalConnections += 1;
355
+ this.connections[s.id] = s;
356
+ this.emit(TUNNEL_EVENT_HTTP_OPEN, this);
357
+ }
358
+
359
+ httpConnectionClosed(s) {
360
+ delete this.connections[s.id];
361
+ this.emit(TUNNEL_EVENT_HTTP_CLOSED, this);
362
+ }
363
+
364
+ httpBasicAuth(req, res) {
365
+ if (this.login || this.password) {
366
+ const user = basicAuth(req);
367
+ if (!user || user.name !== this.login || user.pass !== this.password) {
368
+ logger.debug(LOG_TUNNEL_HTTP_WRON_AUTH);
369
+ this.httpEndFast(req, res, 401, 'Unauthorised', {
370
+ 'WWW-Authenticate': 'Basic real="Buddy"'
371
+ });
372
+ return false;
373
+ }
374
+ }
375
+ return true;
376
+ }
377
+
378
+ httpEndFast(req, res, statusCode, msg, headers = {}) {
379
+ const log = this.httpLog.newRequest(req.method, req.headers, req.url, req.httpVersion, req);
380
+ if (!log) {
381
+ this.httpLog.newResponse(req, statusCode, headers);
382
+ res.statusCode = statusCode;
383
+ Object.keys(headers).forEach((k) => {
384
+ res.setHeader(k, headers[k]);
385
+ });
386
+ res.end(msg);
387
+ } else {
388
+ req.pipe(log.requestBody);
389
+ log.requestBody.pipeToNothing(() => {
390
+ this.httpLog.newResponse(req, statusCode, headers, log);
391
+ res.statusCode = statusCode;
392
+ Object.keys(headers).forEach((k) => {
393
+ res.setHeader(k, headers[k]);
394
+ });
395
+ res.end(msg);
396
+ });
397
+ }
398
+ }
399
+
400
+ httpRateLimit(req, res) {
401
+ const isRateLimited = this.httpLog.isRateLimited(req);
402
+ if (isRateLimited) {
403
+ logger.debug(LOG_TUNNEL_HTTP_RATE_LIMIT);
404
+ this.httpEndFast(req, res, 429, 'Too Many Requests', {
405
+ 'Retry-After': '60'
406
+ });
407
+ return false;
408
+ }
409
+ return true;
410
+ }
411
+
412
+ httpCircuitBreaker(req, res) {
413
+ const isOpen = this.httpLog.isCircuitBreakerOpen();
414
+ if (isOpen) {
415
+ logger.debug(LOG_TUNNEL_HTTP_CIRCUIT_BREAKER_OPEN);
416
+ this.httpEndFast(req, res, 503, 'Service Unavailable', {});
417
+ return false;
418
+ }
419
+ return true;
420
+ }
421
+
422
+ httpUserAgent(req, res) {
423
+ if (this.useragents && this.useragents.length > 0) {
424
+ const ua = req.headers['user-agent'] || '';
425
+ for (let i = 0; i < this.useragents.length; i += 1) {
426
+ const str = this.useragents[i];
427
+ if (isStringRegExp(str)) {
428
+ try {
429
+ const r = new RegExp(str, 'i');
430
+ if (r.test(ua)) return true;
431
+ } catch (err) {
432
+ // do nothing
433
+ }
434
+ } else if (ua.includes(str)) {
435
+ return true;
436
+ }
437
+ }
438
+ logger.debug(LOG_TUNNEL_HTTP_WRONG_USER_AGENTS);
439
+ this.httpEndFast(req, res, 401, 'Unauthorised', {});
440
+ return false;
441
+ }
442
+ return true;
443
+ }
444
+
445
+ targetReconnected() {
446
+ if (this.identify) this.identify.identify();
447
+ }
448
+
449
+ httpLogRequest(logRequest) {
450
+ this.emit(TUNNEL_EVENT_HTTP_REQUEST, this, logRequest);
451
+ }
452
+
453
+ httpLogResponse(logRequest) {
454
+ this.emit(TUNNEL_EVENT_HTTP_RESPONSE, this, logRequest);
455
+ }
456
+
457
+ retryHttpLogRequest(logRequest) {
458
+ if (logRequest.requestBody.tooLarge) return;
459
+ if (logRequest.httpVersion === '2.0') return this.http2server.retryRequest(logRequest);
460
+ return this.http1server.retryRequest(logRequest);
461
+ }
462
+
463
+ httpRequest(req, res) {
464
+ const isAuth = this.httpBasicAuth(req, res)
465
+ && this.httpUserAgent(req, res)
466
+ && this.httpRateLimit(req, res)
467
+ && this.httpCircuitBreaker(req, res);
468
+ if (!isAuth) return;
469
+ const http = new TunnelHttp({
470
+ req,
471
+ res,
472
+ auth: this.targetAuth,
473
+ proto: this.targetProto,
474
+ host: this.targetHost,
475
+ port: this.targetPort,
476
+ hostHeader: this.host,
477
+ timeout: this.timeout,
478
+ verify: this.verify,
479
+ compression: this.compression,
480
+ headers: this.headers,
481
+ serve: this.serve,
482
+ responseHeaders: this.responseHeaders,
483
+ httpIdentify: this.identify.type,
484
+ httpLog: this.httpLog,
485
+ });
486
+ http.pipe().then();
487
+ }
488
+
489
+ tlsSocket(tlsSocket) {
490
+ this.tunnelToTarget(tlsSocket, () => {
491
+ this.emit(TUNNEL_EVENT_TLS_CLOSED, this);
492
+ });
493
+ this.emit(TUNNEL_EVENT_TLS_OPEN, this);
494
+ }
495
+
496
+ canStreamTcp() {
497
+ if (this.type === TUNNEL_TCP) return true;
498
+ return this.type === TUNNEL_TLS && [TLS_TERMINATE_AT_TARGET, TLS_TERMINATE_AT_REGION].includes(this.terminate);
499
+ }
500
+
501
+ canStreamTls() {
502
+ return this.type === TUNNEL_TLS;
503
+ }
504
+
505
+ canStreamSsh() {
506
+ return this.type === TUNNEL_SSH;
507
+ }
508
+
509
+ canStreamHttp() {
510
+ return this.type === TUNNEL_HTTP;
511
+ }
512
+
513
+ sshStreamTcp(stream) {
514
+ if (!this.canStreamTcp()) {
515
+ stream.end();
516
+ return;
517
+ }
518
+ logger.debug(LOG_TUNNEL_TCP_STREAM(this.id));
519
+ this.tunnelToTarget(stream, () => {
520
+ this.emit(TUNNEL_EVENT_TCP_CLOSED, this);
521
+ });
522
+ this.emit(TUNNEL_EVENT_TCP_OPEN, this);
523
+ }
524
+
525
+ sshStreamHttp1(stream, info, ip) {
526
+ if (!this.canStreamHttp()) {
527
+ stream.end();
528
+ return;
529
+ }
530
+ logger.debug(LOG_TUNNEL_HTTP1_STREAM(this.id));
531
+ if (this.http1server) {
532
+ this.http1server.handleSshTunnel(stream, info, ip);
533
+ return;
534
+ }
535
+ stream.end();
536
+ }
537
+
538
+ sshStreamHttp2(stream, info, ip) {
539
+ if (!this.canStreamHttp()) {
540
+ stream.end();
541
+ return;
542
+ }
543
+ logger.debug(LOG_TUNNEL_HTTP2_STREAM(this.id));
544
+ if (this.http2server) {
545
+ this.http2server.handleSshTunnel(stream, info, ip);
546
+ return;
547
+ }
548
+ stream.end();
549
+ }
550
+
551
+ sshStreamSsh(stream) {
552
+ if (!this.canStreamSsh()) {
553
+ stream.end();
554
+ return;
555
+ }
556
+ logger.debug(LOG_TUNNEL_SSH_STREAM(this.id));
557
+ if (this.sshServer) {
558
+ this.sshServer.handleSshTunnel(stream);
559
+ return;
560
+ }
561
+ stream.end();
562
+ }
563
+
564
+ sshStreamTls(stream) {
565
+ if (!this.canStreamTls()) {
566
+ stream.end();
567
+ return;
568
+ }
569
+ if (this.terminate === TLS_TERMINATE_AT_TARGET) {
570
+ logger.debug(LOG_TUNNEL_TLS_TARGET_STREAM(this.id));
571
+ this.sshStreamTcp(stream);
572
+ return;
573
+ }
574
+ if (this.terminate === TLS_TERMINATE_AT_REGION) {
575
+ logger.debug(LOG_TUNNEL_TLS_REGION_STREAM(this.id));
576
+ this.sshStreamTcp(stream);
577
+ return;
578
+ }
579
+ if (this.tls) {
580
+ logger.debug(LOG_TUNNEL_TLS_AGENT_STREAM(this.id));
581
+ this.tls.handleSshTunnel(stream);
582
+ return;
583
+ }
584
+ stream.end();
585
+ }
586
+
587
+ start() {
588
+ if (this.started) return;
589
+ this.started = true;
590
+ logger.info(LOG_STARTING_TUNNEL(this.id));
591
+ // region latency
592
+ this.regionLatency = new TunnelLatency(this.sshIp, this.sshPort);
593
+ this.regionLatency.startChecking();
594
+ // target latency
595
+ if (!this.serve && this.type !== TUNNEL_SSH) {
596
+ this.targetLatency = new TunnelLatency(this.targetHost, this.targetPort);
597
+ this.targetLatency.on(TUNNEL_LATENCY_EVENT_RECONNECTED, () => this.targetReconnected());
598
+ this.targetLatency.startChecking();
599
+ }
600
+ // dns health
601
+ this.dns = new TunnelDns(this.sshIp, this.domain, this.subdomain, this.region, this.sshId);
602
+ this.dns.startChecking();
603
+ if (this.type === TUNNEL_TLS && this.terminate === TLS_TERMINATE_AT_AGENT) {
604
+ // tls
605
+ this.tls = new ServerTls(this.key, this.cert, this.ca);
606
+ this.tls.on(TLS_SOCKET, (socket) => this.tlsSocket(socket));
607
+ } else if (this.type === TUNNEL_HTTP) {
608
+ // http
609
+ this.httpLog = new TunnelHttpLog(this.log, this.circuitBreaker);
610
+ this.httpLog.on(EVENT_TUNNEL_HTTP_NEW_REQUEST, (logRequest) => this.httpLogRequest(logRequest));
611
+ this.httpLog.on(EVENT_TUNNEL_HTTP_NEW_RESPONSE, (logRequest) => this.httpLogResponse(logRequest));
612
+ this.identify = new TunnelIdentification(this.targetProto, this.targetHost, this.targetPort, this.http2 || !!this.serve);
613
+ this.identify.on(EVENT_TUNNEL_IDENTIFIED, (type) => this.httpIdentified(type));
614
+ const host = Format.entryHost(this);
615
+ this.http2server = new ServerHttp2(host);
616
+ this.http2server.on(HTTP2_SESSION_OPEN, (session) => this.httpConnectionOpen(session));
617
+ this.http2server.on(HTTP2_SESSION_CLOSED, (session) => this.httpConnectionClosed(session));
618
+ this.http2server.on(HTTP2_REQUEST, (req, res) => this.httpRequest(req, res));
619
+ this.http1server = new ServerHttp1(host);
620
+ this.http1server.on(HTTP1_SOCKET_OPEN, (socket) => this.httpConnectionOpen(socket));
621
+ this.http1server.on(HTTP1_SOCKET_CLOSED, (socket) => this.httpConnectionClosed(socket));
622
+ this.http1server.on(HTTP1_REQUEST, (req, res) => this.httpRequest(req, res));
623
+ } else if (this.type === TUNNEL_SSH) {
624
+ // ssh server
625
+ this.sshServer = new ServerSsh(this.sshClientUser, this.sshClientPassword, this.sshHostKey);
626
+ }
627
+ // ssh
628
+ this.ssh = new SshClient(this.sshIp, this.sshPort, this.sshUser, this.sshPassword);
629
+ this.ssh.on(SSH_CLIENT_EVENT_CONNECTED, () => this.sshConnected());
630
+ this.ssh.on(SSH_CLIENT_EVENT_DISCONNECTED, () => this.sshDisconnected());
631
+ this.ssh.on(SSH_CLIENT_EVENT_STREAM_TCP, (stream) => this.sshStreamTcp(stream));
632
+ this.ssh.on(SSH_CLIENT_EVENT_STREAM_TLS, (stream) => this.sshStreamTls(stream));
633
+ this.ssh.on(SSH_CLIENT_EVENT_STREAM_HTTP1, (stream, info, ip) => this.sshStreamHttp1(stream, info, ip));
634
+ this.ssh.on(SSH_CLIENT_EVENT_STREAM_HTTP2, (stream, info, ip) => this.sshStreamHttp2(stream, info, ip));
635
+ this.ssh.on(SSH_CLIENT_EVENT_STREAM_SSH, (stream) => this.sshStreamSsh(stream));
636
+ this.ssh.openKeepAlive();
637
+ }
638
+
639
+ stop(emitEvent = true) {
640
+ if (!this.started) return;
641
+ this.started = false;
642
+ logger.info(LOG_STOPPING_TUNNEL(this.id));
643
+ if (emitEvent) this.emit(TUNNEL_EVENT_STOPPED, this);
644
+ if (this.regionLatency) {
645
+ this.regionLatency.removeAllListeners();
646
+ this.regionLatency.stopChecking();
647
+ this.regionLatency = null;
648
+ }
649
+ if (this.dns) {
650
+ this.dns.stopChecking();
651
+ this.dns = null;
652
+ }
653
+ if (this.targetLatency) {
654
+ this.targetLatency.removeAllListeners();
655
+ this.targetLatency.stopChecking();
656
+ this.targetLatency = null;
657
+ }
658
+ if (this.tls) {
659
+ this.tls.removeAllListeners();
660
+ this.tls.stop();
661
+ this.tls = null;
662
+ }
663
+ if (this.httpLog) {
664
+ this.httpLog.removeAllListeners();
665
+ this.httpLog.stop();
666
+ this.httpLog = null;
667
+ }
668
+ if (this.sshServer) {
669
+ this.sshServer.removeAllListeners();
670
+ this.sshServer.stop();
671
+ this.sshServer = null;
672
+ }
673
+ if (this.identify) {
674
+ this.identify.removeAllListeners();
675
+ this.identify.stop();
676
+ this.identify = null;
677
+ }
678
+ if (this.http2server) {
679
+ this.http2server.removeAllListeners();
680
+ this.http2server.stop();
681
+ this.http2server = null;
682
+ }
683
+ if (this.http1server) {
684
+ this.http1server.removeAllListeners();
685
+ this.http1server.stop();
686
+ this.http1server = null;
687
+ }
688
+ if (this.ssh) {
689
+ this.ssh.removeAllListeners();
690
+ this.ssh.closeKeepAlive();
691
+ this.ssh = null;
692
+ }
693
+ }
694
+ }
695
+
696
+ module.exports = Tunnel;