mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-04-29 06:07:55 -04:00
add amt relay events and fixamt recordings #6652
Signed-off-by: si458 <simonsmith5521@gmail.com>
This commit is contained in:
parent
41d9241625
commit
c249282554
132
meshrelay.js
132
meshrelay.js
@ -78,6 +78,72 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
|
||||
}
|
||||
}
|
||||
|
||||
// Record a new entry in a recording log
|
||||
function recordingEntry (logfile, type, flags, data, func, tag) {
|
||||
try {
|
||||
if (logfile.text) {
|
||||
// Text recording format
|
||||
var out = '';
|
||||
const utcDate = new Date(Date.now());
|
||||
if (type == 1) {
|
||||
// End of start
|
||||
out = data + '\r\n' + utcDate.toUTCString() + ', ' + "<<<START>>>" + '\r\n';
|
||||
} else if (type == 3) {
|
||||
// End of log
|
||||
out = utcDate.toUTCString() + ', ' + "<<<END>>>" + '\r\n';
|
||||
} else if (typeof data == 'string') {
|
||||
// Log message
|
||||
if (logfile.text == 1) {
|
||||
out = utcDate.toUTCString() + ', ' + data + '\r\n';
|
||||
} else if (logfile.text == 2) {
|
||||
try {
|
||||
var x = JSON.parse(data);
|
||||
if (typeof x.action == 'string') {
|
||||
if ((x.action == 'chat') && (typeof x.msg == 'string')) { out = utcDate.toUTCString() + ', ' + (((flags & 2) ? '--> ' : '<-- ') + x.msg + '\r\n'); }
|
||||
else if ((x.action == 'file') && (typeof x.name == 'string') && (typeof x.size == 'number')) { out = utcDate.toUTCString() + ', ' + (((flags & 2) ? '--> ' : '<-- ') + "File Transfer" + ', \"' + x.name + '\" (' + x.size + ' ' + "bytes" + ')\r\n'); }
|
||||
} else if (x.ctrlChannel == null) { out = utcDate.toUTCString() + ', ' + data + '\r\n'; }
|
||||
} catch (ex) {
|
||||
out = utcDate.toUTCString() + ', ' + data + '\r\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
// Log this event
|
||||
const block = Buffer.from(out);
|
||||
require('fs').write(logfile.fd, block, 0, block.length, function () { func(logfile, tag); });
|
||||
logfile.size += block.length;
|
||||
} else {
|
||||
// Skip logging this.
|
||||
func(logfile, tag);
|
||||
}
|
||||
} else {
|
||||
// Binary recording format
|
||||
if (typeof data == 'string') {
|
||||
// String write
|
||||
var blockData = Buffer.from(data), header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
|
||||
header.writeInt16BE(type, 0); // Type (1 = Header, 2 = Network Data)
|
||||
header.writeInt16BE(flags, 2); // Flags (1 = Binary, 2 = User)
|
||||
header.writeInt32BE(blockData.length, 4); // Size
|
||||
header.writeIntBE(new Date(), 10, 6); // Time
|
||||
var block = Buffer.concat([header, blockData]);
|
||||
require('fs').write(logfile.fd, block, 0, block.length, function () { func(logfile, tag); });
|
||||
logfile.size += block.length;
|
||||
} else {
|
||||
// Binary write
|
||||
var header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
|
||||
header.writeInt16BE(type, 0); // Type (1 = Header, 2 = Network Data)
|
||||
header.writeInt16BE(flags | 1, 2); // Flags (1 = Binary, 2 = User)
|
||||
header.writeInt32BE(data.length, 4); // Size
|
||||
header.writeIntBE(new Date(), 10, 6); // Time
|
||||
var block = Buffer.concat([header, data]);
|
||||
require('fs').write(logfile.fd, block, 0, block.length, function () { func(logfile, tag); });
|
||||
logfile.size += block.length;
|
||||
}
|
||||
}
|
||||
} catch (ex) { console.log(ex); func(logfile, tag); }
|
||||
}
|
||||
module.exports.recordingEntry = recordingEntry;
|
||||
|
||||
function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||
const currentTime = Date.now();
|
||||
if (cookie) {
|
||||
@ -751,6 +817,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||
setTimeout(function(){ // wait 5 seconds before finishing file for some reason?
|
||||
recordingEntry(logfile, 3, 0, 'MeshCentralMCREC', function (logfile, tag) {
|
||||
parent.parent.fs.closeSync(logfile.fd);
|
||||
parent.parent.debug('relay', 'Relay: Finished recording to file: ' + tag.logfile.filename);
|
||||
|
||||
// Now that the recording file is closed, check if we need to index this file.
|
||||
if (domain.sessionrecording.index && domain.sessionrecording.index !== false) { parent.parent.certificateOperations.acceleratorPerformOperation('indexMcRec', tag.logfile.filename); }
|
||||
@ -796,71 +863,6 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||
if (obj.pid != null) { parent.parent.RemoveAllEventDispatch(obj); }
|
||||
}
|
||||
|
||||
// Record a new entry in a recording log
|
||||
function recordingEntry(logfile, type, flags, data, func, tag) {
|
||||
try {
|
||||
if (logfile.text) {
|
||||
// Text recording format
|
||||
var out = '';
|
||||
const utcDate = new Date(Date.now());
|
||||
if (type == 1) {
|
||||
// End of start
|
||||
out = data + '\r\n' + utcDate.toUTCString() + ', ' + "<<<START>>>" + '\r\n';
|
||||
} else if (type == 3) {
|
||||
// End of log
|
||||
out = utcDate.toUTCString() + ', ' + "<<<END>>>" + '\r\n';
|
||||
} else if (typeof data == 'string') {
|
||||
// Log message
|
||||
if (logfile.text == 1) {
|
||||
out = utcDate.toUTCString() + ', ' + data + '\r\n';
|
||||
} else if (logfile.text == 2) {
|
||||
try {
|
||||
var x = JSON.parse(data);
|
||||
if (typeof x.action == 'string') {
|
||||
if ((x.action == 'chat') && (typeof x.msg == 'string')) { out = utcDate.toUTCString() + ', ' + (((flags & 2) ? '--> ' : '<-- ') + x.msg + '\r\n'); }
|
||||
else if ((x.action == 'file') && (typeof x.name == 'string') && (typeof x.size == 'number')) { out = utcDate.toUTCString() + ', ' + (((flags & 2) ? '--> ' : '<-- ') + "File Transfer" + ', \"' + x.name + '\" (' + x.size + ' ' + "bytes" + ')\r\n'); }
|
||||
} else if (x.ctrlChannel == null) { out = utcDate.toUTCString() + ', ' + data + '\r\n'; }
|
||||
} catch (ex) {
|
||||
out = utcDate.toUTCString() + ', ' + data + '\r\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
// Log this event
|
||||
const block = Buffer.from(out);
|
||||
parent.parent.fs.write(logfile.fd, block, 0, block.length, function () { func(logfile, tag); });
|
||||
logfile.size += block.length;
|
||||
} else {
|
||||
// Skip logging this.
|
||||
func(logfile, tag);
|
||||
}
|
||||
} else {
|
||||
// Binary recording format
|
||||
if (typeof data == 'string') {
|
||||
// String write
|
||||
var blockData = Buffer.from(data), header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
|
||||
header.writeInt16BE(type, 0); // Type (1 = Header, 2 = Network Data)
|
||||
header.writeInt16BE(flags, 2); // Flags (1 = Binary, 2 = User)
|
||||
header.writeInt32BE(blockData.length, 4); // Size
|
||||
header.writeIntBE(new Date(), 10, 6); // Time
|
||||
var block = Buffer.concat([header, blockData]);
|
||||
parent.parent.fs.write(logfile.fd, block, 0, block.length, function () { func(logfile, tag); });
|
||||
logfile.size += block.length;
|
||||
} else {
|
||||
// Binary write
|
||||
var header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
|
||||
header.writeInt16BE(type, 0); // Type (1 = Header, 2 = Network Data)
|
||||
header.writeInt16BE(flags | 1, 2); // Flags (1 = Binary, 2 = User)
|
||||
header.writeInt32BE(data.length, 4); // Size
|
||||
header.writeIntBE(new Date(), 10, 6); // Time
|
||||
var block = Buffer.concat([header, data]);
|
||||
parent.parent.fs.write(logfile.fd, block, 0, block.length, function () { func(logfile, tag); });
|
||||
logfile.size += block.length;
|
||||
}
|
||||
}
|
||||
} catch (ex) { console.log(ex); func(logfile, tag); }
|
||||
}
|
||||
|
||||
// If this session has a expire time, setup the expire timer now.
|
||||
setExpireTimer();
|
||||
|
||||
|
@ -9740,7 +9740,7 @@
|
||||
var rdpflags = 0;
|
||||
for (var i = 1; i < 10; i++) { if ((i != 5) && (Q('d7rdp' + i).checked)) { rdpflags |= (1 << (i - 1)); } }
|
||||
desktopsettings.rdpflags = rdpflags;
|
||||
localStorage.setItem('desktopsettings', JSON.stringify(desktopsettings));
|
||||
putstore('desktopsettings', JSON.stringify(desktopsettings));
|
||||
applyDesktopSettings();
|
||||
updateDesktopButtons();
|
||||
if (desktop) {
|
||||
|
@ -10506,7 +10506,7 @@
|
||||
var rdpflags = 0;
|
||||
for (var i = 1; i < 10; i++) { if ((i != 5) && (Q('d7rdp' + i).checked)) { rdpflags |= (1 << (i - 1)); } }
|
||||
desktopsettings.rdpflags = rdpflags;
|
||||
localStorage.setItem('desktopsettings', JSON.stringify(desktopsettings));
|
||||
putstore('desktopsettings', JSON.stringify(desktopsettings));
|
||||
applyDesktopSettings();
|
||||
updateDesktopButtons();
|
||||
if (desktop) {
|
||||
|
@ -577,7 +577,7 @@
|
||||
var view = new Uint8Array(data.length);
|
||||
for (var i = 0; i < data.length; i++) { view[i] = data.charCodeAt(i); }
|
||||
|
||||
if ((readState == 0) && (rstr2hex(data) == '4100000000000000')) {
|
||||
if ((readState == 0) && (rstr2hex(data).startsWith('4100000000000000'))) {
|
||||
// We are not authenticated, KVM data starts here.
|
||||
readState = 1;
|
||||
if (data.length > 8) { amtDesktop.ProcessBinaryData(view.slice(8).buffer); }
|
||||
|
247
webserver.js
247
webserver.js
@ -4727,8 +4727,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||
// Fetch information about the target
|
||||
obj.db.Get(req.query.host, function (err, docs) {
|
||||
if (docs.length == 0) { console.log('ERR: Node not found'); try { ws.close(); } catch (e) { } return; } // Disconnect websocket
|
||||
var node = docs[0];
|
||||
var xusername = '', xdevicename = '', xdevicename2 = null, node = null;
|
||||
node = docs[0]; xdevicename2 = node.name; xdevicename = '-' + parent.common.makeFilename(node.name); ws.id = getRandomPassword(); ws.time = Date.now();
|
||||
if (!node.intelamt) { console.log('ERR: Not AMT node'); try { ws.close(); } catch (e) { } return; } // Disconnect websocket
|
||||
var ciraconn = parent.mpsserver.GetConnectionToNode(req.query.host, null, false);
|
||||
|
||||
// Check if this user has permission to manage this computer
|
||||
if ((obj.GetNodeRights(user, node.meshid, node._id) & MESHRIGHT_REMOTECONTROL) == 0) { console.log('ERR: Access denied (3)'); try { ws.close(); } catch (e) { } return; }
|
||||
@ -4782,7 +4784,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||
|
||||
if (record == true) {
|
||||
var now = new Date(Date.now());
|
||||
var recFilename = 'relaysession' + ((domain.id == '') ? '' : '-') + domain.id + '-' + now.getUTCFullYear() + '-' + obj.common.zeroPad(now.getUTCMonth() + 1, 2) + '-' + obj.common.zeroPad(now.getUTCDate(), 2) + '-' + obj.common.zeroPad(now.getUTCHours(), 2) + '-' + obj.common.zeroPad(now.getUTCMinutes(), 2) + '-' + obj.common.zeroPad(now.getUTCSeconds(), 2) + '-' + getRandomPassword() + '.mcrec'
|
||||
// Get the username and make it acceptable as a filename
|
||||
if (user._id) { xusername = '-' + parent.common.makeFilename(user._id.split('/')[2]); }
|
||||
var xsessionid = ws.id;
|
||||
var recFilename = 'relaysession' + ((domain.id == '') ? '' : '-') + domain.id + '-' + now.getUTCFullYear() + '-' + obj.common.zeroPad(now.getUTCMonth() + 1, 2) + '-' + obj.common.zeroPad(now.getUTCDate(), 2) + '-' + obj.common.zeroPad(now.getUTCHours(), 2) + '-' + obj.common.zeroPad(now.getUTCMinutes(), 2) + '-' + obj.common.zeroPad(now.getUTCSeconds(), 2) + xusername + xdevicename + '-' + xsessionid + '.mcrec';
|
||||
var recFullFilename = null;
|
||||
if (domain.sessionrecording.filepath) {
|
||||
try { obj.fs.mkdirSync(domain.sessionrecording.filepath); } catch (e) { }
|
||||
@ -4794,16 +4799,32 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||
var fd = obj.fs.openSync(recFullFilename, 'w');
|
||||
if (fd != null) {
|
||||
// Write the recording file header
|
||||
var firstBlock = JSON.stringify({ magic: 'MeshCentralRelaySession', ver: 1, userid: user._id, username: user.name, ipaddr: req.clientIp, nodeid: node._id, intelamt: true, protocol: (req.query.p == 2) ? 101 : 100, time: new Date().toLocaleString() })
|
||||
recordingEntry(fd, 1, 0, firstBlock, function () { });
|
||||
ws.logfile = { fd: fd, lock: false };
|
||||
parent.debug('relay', 'Relay: Started recording to file: ' + recFullFilename);
|
||||
var metadata = {
|
||||
magic: 'MeshCentralRelaySession',
|
||||
ver: 1,
|
||||
userid: user._id,
|
||||
username: user.name,
|
||||
sessionid: ws.id,
|
||||
ipaddr1: req.clientIp,
|
||||
time: new Date().toLocaleString(),
|
||||
protocol: (req.query.p == 2) ? 101 : 100,
|
||||
nodeid: node._id,
|
||||
intelamt: true
|
||||
};
|
||||
if (ciraconn != null) { metadata.ipaddr2 = ciraconn.remoteAddr; }
|
||||
else if ((conn & 4) != 0) { metadata.ipaddr2 = node.host; }
|
||||
if (xdevicename2 != null) { metadata.devicename = xdevicename2; }
|
||||
var firstBlock = JSON.stringify(metadata)
|
||||
ws.logfile = { fd: fd, lock: false, filename: recFullFilename, startTime: Date.now(), size: 0, text: 0, req: req };
|
||||
obj.meshRelayHandler.recordingEntry(ws.logfile, 1, 0, firstBlock, function () { });
|
||||
if (node != null) { ws.logfile.nodeid = node._id; ws.logfile.meshid = node.meshid; ws.logfile.name = node.name; ws.logfile.icon = node.icon; }
|
||||
if (req.query.p == 2) { ws.send(Buffer.from(String.fromCharCode(0xF0), 'binary')); } // Intel AMT Redirection: Indicate the session is being recorded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If Intel AMT CIRA connection is available, use it
|
||||
var ciraconn = parent.mpsserver.GetConnectionToNode(req.query.host, null, false);
|
||||
if (ciraconn != null) {
|
||||
parent.debug('web', 'Opening relay CIRA channel connection to ' + req.query.host + '.');
|
||||
|
||||
@ -4865,7 +4886,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||
try { ws.send(data); } catch (e) { }
|
||||
} else {
|
||||
// Log to recording file
|
||||
recordingEntry(ws.logfile.fd, 2, 0, data, function () { try { ws.send(data); } catch (ex) { console.log(ex); } }); // TODO: Add TLS support
|
||||
obj.meshRelayHandler.recordingEntry(ws.logfile, 2, 0, data, function () { try { ws.send(data); } catch (ex) { console.log(ex); } }); // TODO: Add TLS support
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -4897,7 +4918,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||
try { ws.send(data); } catch (e) { }
|
||||
} else {
|
||||
// Log to recording file
|
||||
recordingEntry(ws.logfile.fd, 2, 0, data, function () { try { ws.send(data); } catch (ex) { console.log(ex); } });
|
||||
obj.meshRelayHandler.recordingEntry(ws.logfile, 2, 0, data, function () { try { ws.send(data); } catch (ex) { console.log(ex); } });
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -4921,7 +4942,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||
try { ws.forwardclient.write(data); } catch (ex) { }
|
||||
} else {
|
||||
// Log to recording file
|
||||
recordingEntry(ws.logfile.fd, 2, 2, data, function () { try { ws.forwardclient.write(data); } catch (ex) { } });
|
||||
obj.meshRelayHandler.recordingEntry(ws.logfile, 2, 2, data, function () { try { ws.forwardclient.write(data); } catch (ex) { } });
|
||||
}
|
||||
});
|
||||
|
||||
@ -4930,6 +4951,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||
console.log('CIRA server websocket error from ' + req.clientIp + ', ' + err.toString().split('\r')[0] + '.');
|
||||
parent.debug('webrelay', 'Websocket relay closed on error.');
|
||||
|
||||
// Log the disconnection
|
||||
if (ws.time) {
|
||||
var msg = 'Ended relay session', msgid = 9, ip = ((ciraconn != null) ? ciraconn.remoteAddr : (((conn & 4) != 0) ? node.host : req.clientIp));
|
||||
var nodeid = node._id;
|
||||
var meshid = node.meshid;
|
||||
if (user) {
|
||||
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: user._id, username: user.name, msgid: msgid, msgArgs: [ws.id, req.clientIp, ip, Math.floor((Date.now() - ws.time) / 1000)], msg: msg + ' \"' + ws.id + '\" from ' + req.clientIp + ' to ' + ip + ', ' + Math.floor((Date.now() - ws.time) / 1000) + ' second(s)', protocol: ((req.query.p == 2) ? 101 : 100), nodeid: nodeid };
|
||||
obj.parent.DispatchEvent(['*', user._id, nodeid, meshid], obj, event);
|
||||
}
|
||||
}
|
||||
|
||||
// Websocket closed, close the CIRA channel and TLS session.
|
||||
if (ws.forwardclient) {
|
||||
if (ws.forwardclient.close) { ws.forwardclient.close(); } // NonTLS, close the CIRA channel
|
||||
@ -4939,13 +4971,47 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||
}
|
||||
|
||||
// Close the recording file
|
||||
if (ws.logfile != null) { recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd, ws) { obj.fs.close(fd); delete ws.logfile; }, ws); }
|
||||
if (ws.logfile != null) {
|
||||
setTimeout(function(){ // wait 5 seconds before finishing file for some reason?
|
||||
obj.meshRelayHandler.recordingEntry(ws.logfile, 3, 0, 'MeshCentralMCREC', function (logfile, ws) {
|
||||
obj.fs.close(logfile.fd);
|
||||
parent.debug('relay', 'Relay: Finished recording to file: ' + ws.logfile.filename);
|
||||
// Compute session length
|
||||
var sessionLength = null;
|
||||
if (ws.logfile.startTime != null) { sessionLength = Math.round((Date.now() - ws.logfile.startTime) / 1000); }
|
||||
// Add a event entry about this recording
|
||||
var basefile = parent.path.basename(ws.logfile.filename);
|
||||
var event = { etype: 'relay', action: 'recording', domain: domain.id, nodeid: ws.logfile.nodeid, msg: "Finished recording session" + (sessionLength ? (', ' + sessionLength + ' second(s)') : ''), filename: basefile, size: ws.logfile.size };
|
||||
if (user) { event.userids = [user._id]; } else if (peer.user) { event.userids = [peer.user._id]; }
|
||||
var xprotocol = (((ws.logfile.req == null) || (ws.logfile.req.query == null)) ? null : (ws.logfile.req.query.p == 2) ? 101 : 100);
|
||||
if (xprotocol != null) { event.protocol = parseInt(xprotocol); }
|
||||
var mesh = obj.meshes[ws.logfile.meshid];
|
||||
if (mesh != null) { event.meshname = mesh.name; event.meshid = mesh._id; }
|
||||
if (ws.logfile.startTime) { event.startTime = ws.logfile.startTime; event.lengthTime = sessionLength; }
|
||||
if (ws.logfile.name) { event.name = ws.logfile.name; }
|
||||
if (ws.logfile.icon) { event.icon = ws.logfile.icon; }
|
||||
obj.parent.DispatchEvent(['*', 'recording', ws.logfile.nodeid, ws.logfile.meshid], obj, event);
|
||||
delete ws.logfile;
|
||||
}, ws);
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
|
||||
// If the web socket is closed, close the associated TCP connection.
|
||||
ws.on('close', function (req) {
|
||||
ws.on('close', function () {
|
||||
parent.debug('webrelay', 'Websocket relay closed.');
|
||||
|
||||
// Log the disconnection
|
||||
if (ws.time) {
|
||||
var msg = 'Ended relay session', msgid = 9, ip = ((ciraconn != null) ? ciraconn.remoteAddr : (((conn & 4) != 0) ? node.host : req.clientIp));
|
||||
var nodeid = node._id;
|
||||
var meshid = node.meshid;
|
||||
if (user) {
|
||||
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: user._id, username: user.name, msgid: msgid, msgArgs: [ws.id, req.clientIp, ip, Math.floor((Date.now() - ws.time) / 1000)], msg: msg + ' \"' + ws.id + '\" from ' + req.clientIp + ' to ' + ip + ', ' + Math.floor((Date.now() - ws.time) / 1000) + ' second(s)', protocol: ((req.query.p == 2) ? 101 : 100), nodeid: nodeid };
|
||||
obj.parent.DispatchEvent(['*', user._id, nodeid, meshid], obj, event);
|
||||
}
|
||||
}
|
||||
|
||||
// Websocket closed, close the CIRA channel and TLS session.
|
||||
if (ws.forwardclient) {
|
||||
if (ws.forwardclient.close) { ws.forwardclient.close(); } // NonTLS, close the CIRA channel
|
||||
@ -4955,7 +5021,30 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||
}
|
||||
|
||||
// Close the recording file
|
||||
if (ws.logfile != null) { recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd, ws) { obj.fs.close(fd); delete ws.logfile; }, ws); }
|
||||
if (ws.logfile != null) {
|
||||
setTimeout(function(){ // wait 5 seconds before finishing file for some reason?
|
||||
obj.meshRelayHandler.recordingEntry(ws.logfile, 3, 0, 'MeshCentralMCREC', function (logfile, ws) {
|
||||
obj.fs.close(logfile.fd);
|
||||
parent.debug('relay', 'Relay1: Finished recording to file: ' + ws.logfile.filename);
|
||||
// Compute session length
|
||||
var sessionLength = null;
|
||||
if (ws.logfile.startTime != null) { sessionLength = Math.round((Date.now() - ws.logfile.startTime) / 1000); }
|
||||
// Add a event entry about this recording
|
||||
var basefile = parent.path.basename(ws.logfile.filename);
|
||||
var event = { etype: 'relay', action: 'recording', domain: domain.id, nodeid: ws.logfile.nodeid, msg: "Finished recording session" + (sessionLength ? (', ' + sessionLength + ' second(s)') : ''), filename: basefile, size: ws.logfile.size };
|
||||
if (user) { event.userids = [user._id]; }
|
||||
var xprotocol = (((ws.logfile.req == null) || (ws.logfile.req.query == null)) ? null : (ws.logfile.req.query.p == 2) ? 101 : 100);
|
||||
if (xprotocol != null) { event.protocol = parseInt(xprotocol); }
|
||||
var mesh = obj.meshes[ws.logfile.meshid];
|
||||
if (mesh != null) { event.meshname = mesh.name; event.meshid = mesh._id; }
|
||||
if (ws.logfile.startTime) { event.startTime = ws.logfile.startTime; event.lengthTime = sessionLength; }
|
||||
if (ws.logfile.name) { event.name = ws.logfile.name; }
|
||||
if (ws.logfile.icon) { event.icon = ws.logfile.icon; }
|
||||
obj.parent.DispatchEvent(['*', 'recording', ws.logfile.nodeid, ws.logfile.meshid], obj, event);
|
||||
delete ws.logfile;
|
||||
}, ws);
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
|
||||
// Note that here, req.query.p: 1 = WSMAN with server auth, 2 = REDIR with server auth, 3 = WSMAN without server auth, 4 = REDIR with server auth
|
||||
@ -4970,12 +5059,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||
ws.interceptor = obj.interceptor.CreateRedirInterceptor({ user: node.intelamt.user, pass: node.intelamt.pass });
|
||||
ws.interceptor.blockAmtStorage = true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If Intel AMT direct connection is possible, option a direct socket
|
||||
if ((conn & 4) != 0) { // We got a new web socket connection, initiate a TCP connection to the target Intel AMT host/port.
|
||||
} else if ((conn & 4) != 0) { // If Intel AMT direct connection is possible, option a direct socket
|
||||
// We got a new web socket connection, initiate a TCP connection to the target Intel AMT host/port.
|
||||
parent.debug('webrelay', 'Opening relay TCP socket connection to ' + req.query.host + '.');
|
||||
|
||||
// When data is received from the web socket, forward the data into the associated TCP connection.
|
||||
@ -4991,7 +5076,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||
try { ws.forwardclient.write(msg); } catch (ex) { }
|
||||
} else {
|
||||
// Log to recording file
|
||||
recordingEntry(ws.logfile.fd, 2, 2, msg, function () { try { ws.forwardclient.write(msg); } catch (ex) { } });
|
||||
obj.meshRelayHandler.recordingEntry(ws.logfile, 2, 2, msg, function () { try { ws.forwardclient.write(msg); } catch (ex) { } });
|
||||
}
|
||||
});
|
||||
|
||||
@ -4999,28 +5084,84 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||
ws.on('error', function (err) {
|
||||
console.log('Error with relay web socket connection from ' + req.clientIp + ', ' + err.toString().split('\r')[0] + '.');
|
||||
parent.debug('webrelay', 'Error with relay web socket connection from ' + req.clientIp + '.');
|
||||
// Log the disconnection
|
||||
if (ws.time) {
|
||||
var msg = 'Ended relay session', msgid = 9, ip = ((ciraconn != null) ? ciraconn.remoteAddr : (((conn & 4) != 0) ? node.host : req.clientIp));
|
||||
var nodeid = node._id;
|
||||
var meshid = node.meshid;
|
||||
if (user) {
|
||||
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: user._id, username: user.name, msgid: msgid, msgArgs: [ws.id, req.clientIp, ip, Math.floor((Date.now() - ws.time) / 1000)], msg: msg + ' \"' + ws.id + '\" from ' + req.clientIp + ' to ' + ip + ', ' + Math.floor((Date.now() - ws.time) / 1000) + ' second(s)', protocol: ((req.query.p == 2) ? 101 : 100), nodeid: nodeid };
|
||||
obj.parent.DispatchEvent(['*', user._id, nodeid, meshid], obj, event);
|
||||
}
|
||||
}
|
||||
if (ws.forwardclient) { try { ws.forwardclient.destroy(); } catch (e) { } }
|
||||
|
||||
// Close the recording file
|
||||
if (ws.logfile != null) {
|
||||
recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd) {
|
||||
obj.fs.close(fd);
|
||||
ws.logfile = null;
|
||||
});
|
||||
setTimeout(function(){ // wait 5 seconds before finishing file for some reason?
|
||||
obj.meshRelayHandler.recordingEntry(ws.logfile, 3, 0, 'MeshCentralMCREC', function (logfile, ws) {
|
||||
obj.fs.close(logfile.fd);
|
||||
parent.debug('relay', 'Relay: Finished recording to file: ' + ws.logfile.filename);
|
||||
// Compute session length
|
||||
var sessionLength = null;
|
||||
if (ws.logfile.startTime != null) { sessionLength = Math.round((Date.now() - ws.logfile.startTime) / 1000); }
|
||||
// Add a event entry about this recording
|
||||
var basefile = parent.path.basename(ws.logfile.filename);
|
||||
var event = { etype: 'relay', action: 'recording', domain: domain.id, nodeid: ws.logfile.nodeid, msg: "Finished recording session" + (sessionLength ? (', ' + sessionLength + ' second(s)') : ''), filename: basefile, size: ws.logfile.size };
|
||||
if (user) { event.userids = [user._id]; } else if (peer.user) { event.userids = [peer.user._id]; }
|
||||
var xprotocol = (((ws.logfile.req == null) || (ws.logfile.req.query == null)) ? null : (ws.logfile.req.query.p == 2) ? 101 : 100);
|
||||
if (xprotocol != null) { event.protocol = parseInt(xprotocol); }
|
||||
var mesh = obj.meshes[ws.logfile.meshid];
|
||||
if (mesh != null) { event.meshname = mesh.name; event.meshid = mesh._id; }
|
||||
if (ws.logfile.startTime) { event.startTime = ws.logfile.startTime; event.lengthTime = sessionLength; }
|
||||
if (ws.logfile.name) { event.name = ws.logfile.name; }
|
||||
if (ws.logfile.icon) { event.icon = ws.logfile.icon; }
|
||||
obj.parent.DispatchEvent(['*', 'recording', ws.logfile.nodeid, ws.logfile.meshid], obj, event);
|
||||
delete ws.logfile;
|
||||
}, ws);
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
|
||||
// If the web socket is closed, close the associated TCP connection.
|
||||
ws.on('close', function () {
|
||||
parent.debug('webrelay', 'Closing relay web socket connection to ' + req.query.host + '.');
|
||||
// Log the disconnection
|
||||
if (ws.time) {
|
||||
var msg = 'Ended relay session', msgid = 9, ip = ((ciraconn != null) ? ciraconn.remoteAddr : (((conn & 4) != 0) ? node.host : req.clientIp));
|
||||
var nodeid = node._id;
|
||||
var meshid = node.meshid;
|
||||
if (user) {
|
||||
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: user._id, username: user.name, msgid: msgid, msgArgs: [ws.id, req.clientIp, ip, Math.floor((Date.now() - ws.time) / 1000)], msg: msg + ' \"' + ws.id + '\" from ' + req.clientIp + ' to ' + ip + ', ' + Math.floor((Date.now() - ws.time) / 1000) + ' second(s)', protocol: ((req.query.p == 2) ? 101 : 100), nodeid: nodeid };
|
||||
obj.parent.DispatchEvent(['*', user._id, nodeid, meshid], obj, event);
|
||||
}
|
||||
}
|
||||
if (ws.forwardclient) { try { ws.forwardclient.destroy(); } catch (e) { } }
|
||||
|
||||
// Close the recording file
|
||||
if (ws.logfile != null) {
|
||||
recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd) {
|
||||
obj.fs.close(fd);
|
||||
ws.logfile = null;
|
||||
});
|
||||
setTimeout(function(){ // wait 5 seconds before finishing file for some reason?
|
||||
obj.meshRelayHandler.recordingEntry(ws.logfile, 3, 0, 'MeshCentralMCREC', function (logfile, ws) {
|
||||
obj.fs.close(logfile.fd);
|
||||
parent.debug('relay', 'Relay: Finished recording to file: ' + ws.logfile.filename);
|
||||
// Compute session length
|
||||
var sessionLength = null;
|
||||
if (ws.logfile.startTime != null) { sessionLength = Math.round((Date.now() - ws.logfile.startTime) / 1000); }
|
||||
// Add a event entry about this recording
|
||||
var basefile = parent.path.basename(ws.logfile.filename);
|
||||
var event = { etype: 'relay', action: 'recording', domain: domain.id, nodeid: ws.logfile.nodeid, msg: "Finished recording session" + (sessionLength ? (', ' + sessionLength + ' second(s)') : ''), filename: basefile, size: ws.logfile.size };
|
||||
if (user) { event.userids = [user._id]; } else if (peer.user) { event.userids = [peer.user._id]; }
|
||||
var xprotocol = (((ws.logfile.req == null) || (ws.logfile.req.query == null)) ? null : (ws.logfile.req.query.p == 2) ? 101 : 100);
|
||||
if (xprotocol != null) { event.protocol = parseInt(xprotocol); }
|
||||
var mesh = obj.meshes[ws.logfile.meshid];
|
||||
if (mesh != null) { event.meshname = mesh.name; event.meshid = mesh._id; }
|
||||
if (ws.logfile.startTime) { event.startTime = ws.logfile.startTime; event.lengthTime = sessionLength; }
|
||||
if (ws.logfile.name) { event.name = ws.logfile.name; }
|
||||
if (ws.logfile.icon) { event.icon = ws.logfile.icon; }
|
||||
obj.parent.DispatchEvent(['*', 'recording', ws.logfile.nodeid, ws.logfile.meshid], obj, event);
|
||||
delete ws.logfile;
|
||||
}, ws);
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
|
||||
@ -5064,7 +5205,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||
try { ws.send(data); } catch (e) { }
|
||||
} else {
|
||||
// Log to recording file
|
||||
recordingEntry(ws.logfile.fd, 2, 0, data, function () { try { ws.send(data); } catch (e) { } });
|
||||
obj.meshRelayHandler.recordingEntry(ws.logfile, 2, 0, data, function () { try { ws.send(data); } catch (e) { } });
|
||||
}
|
||||
});
|
||||
|
||||
@ -5092,9 +5233,30 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||
ws._socket.resume();
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Log the connection
|
||||
if (user != null) {
|
||||
var msg = 'Started relay session', msgid = 13, ip = ((ciraconn != null) ? ciraconn.remoteAddr : (((conn & 4) != 0) ? node.host : req.clientIp));
|
||||
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: user._id, username: user.name, msgid: msgid, msgArgs: [ws.id, req.clientIp, ip], msg: msg + ' \"' + obj.id + '\" from ' + req.clientIp + ' to ' + ip, protocol: ((req.query.p == 2) ? 101 : 100), nodeid: node._id };
|
||||
obj.parent.DispatchEvent(['*', user._id], obj, event);
|
||||
|
||||
// Update user last access time
|
||||
if ((user != null)) {
|
||||
const timeNow = Math.floor(Date.now() / 1000);
|
||||
if (user.access < (timeNow - 300)) { // Only update user access time if longer than 5 minutes
|
||||
user.access = timeNow;
|
||||
obj.parent.db.SetUser(user);
|
||||
|
||||
// Event the change
|
||||
var message = { etype: 'user', userid: user._id, username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', domain: domain.id, nolog: 1 };
|
||||
if (parent.db.changeStream) { message.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
|
||||
var targets = ['*', 'server-users', user._id];
|
||||
if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
|
||||
obj.parent.DispatchEvent(targets, obj, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -9569,7 +9731,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||
// Generate a random Intel AMT password
|
||||
function checkAmtPassword(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
|
||||
function getRandomAmtPassword() { var p; do { p = Buffer.from(obj.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); } while (checkAmtPassword(p) == false); return p; }
|
||||
function getRandomPassword() { return Buffer.from(obj.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); }
|
||||
function getRandomPassword() { return Buffer.from(obj.crypto.randomBytes(9), 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); }
|
||||
function getRandomLowerCase(len) { var r = '', random = obj.crypto.randomBytes(len); for (var i = 0; i < len; i++) { r += String.fromCharCode(97 + (random[i] % 26)); } return r; }
|
||||
|
||||
// Generate a 8 digit integer with even random probability for each value.
|
||||
@ -9594,31 +9756,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||
}
|
||||
}
|
||||
|
||||
// Record a new entry in a recording log
|
||||
function recordingEntry(fd, type, flags, data, func, tag) {
|
||||
try {
|
||||
if (typeof data == 'string') {
|
||||
// String write
|
||||
var blockData = Buffer.from(data), header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
|
||||
header.writeInt16BE(type, 0); // Type (1 = Header, 2 = Network Data)
|
||||
header.writeInt16BE(flags, 2); // Flags (1 = Binary, 2 = User)
|
||||
header.writeInt32BE(blockData.length, 4); // Size
|
||||
header.writeIntBE(new Date(), 10, 6); // Time
|
||||
var block = Buffer.concat([header, blockData]);
|
||||
obj.fs.write(fd, block, 0, block.length, function () { func(fd, tag); });
|
||||
} else {
|
||||
// Binary write
|
||||
var header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
|
||||
header.writeInt16BE(type, 0); // Type (1 = Header, 2 = Network Data)
|
||||
header.writeInt16BE(flags | 1, 2); // Flags (1 = Binary, 2 = User)
|
||||
header.writeInt32BE(data.length, 4); // Size
|
||||
header.writeIntBE(new Date(), 10, 6); // Time
|
||||
var block = Buffer.concat([header, data]);
|
||||
obj.fs.write(fd, block, 0, block.length, function () { func(fd, tag); });
|
||||
}
|
||||
} catch (ex) { console.log(ex); func(fd, tag); }
|
||||
}
|
||||
|
||||
// Perform a IP match against a list
|
||||
function isIPMatch(ip, matchList) {
|
||||
const ipcheck = require('ipcheck');
|
||||
|
Loading…
x
Reference in New Issue
Block a user