Add configuration option to restrict connections to specified subnets
Signed-off-by: Matt Oswalt <matt@keepingitclassless.net>
This commit is contained in:
parent
9a96637cb4
commit
ccbe327cd6
5 changed files with 30 additions and 3 deletions
|
|
@ -111,6 +111,8 @@ docker run --name webssh2 -d -p 2222:2222 -v `pwd`/app/config.json:/usr/src/conf
|
||||||
|
|
||||||
* **ssh.keepaliveCountMax** - _integer_ - How many consecutive, unanswered SSH-level keepalive packets that can be sent to the server before disconnection (similar to OpenSSH's ServerAliveCountMax config option). **Default:** 10.
|
* **ssh.keepaliveCountMax** - _integer_ - How many consecutive, unanswered SSH-level keepalive packets that can be sent to the server before disconnection (similar to OpenSSH's ServerAliveCountMax config option). **Default:** 10.
|
||||||
|
|
||||||
|
* **allowedSubnets** - _array_ - A list of subnets that the server is allowed to connect to via SSH. An empty array means all subnets are permitted; no restriction. **Default:** empty array.
|
||||||
|
|
||||||
* **terminal.cursorBlink** - _boolean_ - Cursor blinks (true), does not (false) **Default:** true.
|
* **terminal.cursorBlink** - _boolean_ - Cursor blinks (true), does not (false) **Default:** true.
|
||||||
|
|
||||||
* **terminal.scrollback** - _integer_ - Lines in the scrollback buffer. **Default:** 10000.
|
* **terminal.scrollback** - _integer_ - Lines in the scrollback buffer. **Default:** 10000.
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@
|
||||||
"term": "xterm-color",
|
"term": "xterm-color",
|
||||||
"readyTimeout": 20000,
|
"readyTimeout": 20000,
|
||||||
"keepaliveInterval": 120000,
|
"keepaliveInterval": 120000,
|
||||||
"keepaliveCountMax": 10
|
"keepaliveCountMax": 10,
|
||||||
|
"allowedSubnets": []
|
||||||
},
|
},
|
||||||
"terminal": {
|
"terminal": {
|
||||||
"cursorBlink": true,
|
"cursorBlink": true,
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,8 @@
|
||||||
"validator": "~12.0.0",
|
"validator": "~12.0.0",
|
||||||
"xterm-addon-fit": "^0.3.0",
|
"xterm-addon-fit": "^0.3.0",
|
||||||
"xterm-addon-search": "^0.3.0",
|
"xterm-addon-search": "^0.3.0",
|
||||||
"xterm-addon-web-links": "^0.2.1"
|
"xterm-addon-web-links": "^0.2.1",
|
||||||
|
"netmask": "1.0.6"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node index.js",
|
"start": "node index.js",
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ let config = {
|
||||||
term: 'xterm-color',
|
term: 'xterm-color',
|
||||||
readyTimeout: 20000,
|
readyTimeout: 20000,
|
||||||
keepaliveInterval: 120000,
|
keepaliveInterval: 120000,
|
||||||
keepaliveCountMax: 10
|
keepaliveCountMax: 10,
|
||||||
|
allowedSubnets: []
|
||||||
},
|
},
|
||||||
terminal: {
|
terminal: {
|
||||||
cursorBlink: true,
|
cursorBlink: true,
|
||||||
|
|
@ -153,6 +154,7 @@ app.get('/ssh/host/:host?', function (req, res, next) {
|
||||||
algorithms: config.algorithms,
|
algorithms: config.algorithms,
|
||||||
keepaliveInterval: config.ssh.keepaliveInterval,
|
keepaliveInterval: config.ssh.keepaliveInterval,
|
||||||
keepaliveCountMax: config.ssh.keepaliveCountMax,
|
keepaliveCountMax: config.ssh.keepaliveCountMax,
|
||||||
|
allowedSubnets: config.ssh.allowedSubnets,
|
||||||
term: (/^(([a-z]|[A-Z]|[0-9]|[!^(){}\-_~])+)?\w$/.test(req.query.sshterm) &&
|
term: (/^(([a-z]|[A-Z]|[0-9]|[!^(){}\-_~])+)?\w$/.test(req.query.sshterm) &&
|
||||||
req.query.sshterm) || config.ssh.term,
|
req.query.sshterm) || config.ssh.term,
|
||||||
terminal: {
|
terminal: {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
var debug = require('debug')
|
var debug = require('debug')
|
||||||
var debugWebSSH2 = require('debug')('WebSSH2')
|
var debugWebSSH2 = require('debug')('WebSSH2')
|
||||||
var SSH = require('ssh2').Client
|
var SSH = require('ssh2').Client
|
||||||
|
var Netmask = require('netmask').Netmask
|
||||||
// var fs = require('fs')
|
// var fs = require('fs')
|
||||||
// var hostkeys = JSON.parse(fs.readFileSync('./hostkeyhashes.json', 'utf8'))
|
// var hostkeys = JSON.parse(fs.readFileSync('./hostkeyhashes.json', 'utf8'))
|
||||||
var termCols, termRows
|
var termCols, termRows
|
||||||
|
|
@ -21,6 +22,26 @@ module.exports = function socket (socket) {
|
||||||
socket.disconnect(true)
|
socket.disconnect(true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If configured, check that requsted host is in a permitted subnet
|
||||||
|
if (socket.request.session.ssh.allowedSubnets.length > 0) {
|
||||||
|
var permitted = false;
|
||||||
|
for (const subnet of socket.request.session.ssh.allowedSubnets) {
|
||||||
|
var subnetBlock = new Netmask(subnet);
|
||||||
|
if (subnetBlock.contains(socket.request.session.ssh.host)) {
|
||||||
|
permitted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!permitted) {
|
||||||
|
socket.emit('401 UNAUTHORIZED')
|
||||||
|
socket.emit('status', 'SSH CONNECTION ESTABLISHED')
|
||||||
|
debugWebSSH2('SOCKET: Requested host outside configured subnets / REJECTED')
|
||||||
|
socket.disconnect(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var conn = new SSH()
|
var conn = new SSH()
|
||||||
socket.on('geometry', function socketOnGeometry (cols, rows) {
|
socket.on('geometry', function socketOnGeometry (cols, rows) {
|
||||||
termCols = cols
|
termCols = cols
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue