From f53ad45b502bd23fe906fedc338909b0938cf9f6 Mon Sep 17 00:00:00 2001 From: Brian White Date: Sun, 8 Aug 2021 13:11:36 -0400 Subject: [PATCH] Server: allow injected sockets Fixes: https://github.com/mscdex/ssh2/issues/1027 --- README.md | 2 ++ lib/server.js | 4 ++++ test/test-misc-client-server.js | 32 +++++++++++++++++++++++++++++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 56bb8270..b75a0cf2 100644 --- a/README.md +++ b/README.md @@ -1070,6 +1070,8 @@ You can find more examples in the `examples` directory of this repository. * **debug** - _function_ - Set this to a function that receives a single string argument to get detailed (local) debug information. **Default:** (none) +* **injectSocket**(< _DuplexStream_ >socket) - Injects a bidirectional stream as though it were a TCP socket connection. Additionally, `socket` should include `net.Socket`-like properties to ensure the best compatibility (e.g. `socket.remoteAddress`, `socket.remotePort`, `socket.remoteFamily`). + #### Connection events * **authentication**(< _AuthContext_ >ctx) - The client has requested authentication. `ctx.username` contains the client username, `ctx.method` contains the requested authentication method, and `ctx.accept()` and `ctx.reject([< Array >authMethodsLeft[, < Boolean >isPartialSuccess]])` are used to accept or reject the authentication request respectively. `abort` is emitted if the client aborts the authentication request. Other properties/methods available on `ctx` depends on the `ctx.method` of authentication the client has requested: diff --git a/lib/server.js b/lib/server.js index 9137cdf9..11c15a19 100644 --- a/lib/server.js +++ b/lib/server.js @@ -351,6 +351,10 @@ class Server extends EventEmitter { this.maxConnections = Infinity; } + injectSocket(socket) { + this._srv.emit('connection', socket); + } + listen(...args) { this._srv.listen(...args); return this; diff --git a/test/test-misc-client-server.js b/test/test-misc-client-server.js index 77da58cf..e3b77915 100644 --- a/test/test-misc-client-server.js +++ b/test/test-misc-client-server.js @@ -1,10 +1,11 @@ 'use strict'; const assert = require('assert'); +const { createHash } = require('crypto'); const http = require('http'); const https = require('https'); -const { createHash } = require('crypto'); const net = require('net'); +const { Transform } = require('stream'); const { inspect } = require('util'); const Client = require('../lib/client.js'); @@ -1397,3 +1398,32 @@ const setup = setupSimple.bind(undefined, debug); assert.strictEqual(client._chanMgr._count, 0); })); } + +{ + // Allow injected sockets + + const socket = new Transform({ + emitClose: true, + autoDestroy: true, + transform: (chunk, encoding, cb) => { + cb(); + }, + }); + socket.remoteAddress = '127.0.0.1'; + socket.remotePort = '12345'; + socket.remoteFamily = 'IPv4'; + socket.push(Buffer.from('SSH-2.0-foo\r\n')); + + const server = new Server(serverCfg); + server.on('connection', mustCall((conn, info) => { + assert.strictEqual(info.header.versions.software, 'foo'); + assert.strictEqual(info.ip, '127.0.0.1'); + assert.strictEqual(info.port, '12345'); + assert.strictEqual(info.family, 'IPv4'); + conn.on('ready', mustNotCall()); + conn.on('close', mustCall()); + socket.end(); + })); + server.injectSocket(socket); +} +