From 7927892855522b77a07d0c44903fe3a3cc77e5cb Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Tue, 6 Aug 2019 13:27:24 -0700 Subject: [PATCH] Improved session recording and logs. --- meshrelay.js | 58 +++++++++++++++++--------- public/scripts/agent-redir-ws-0.1.0.js | 4 +- sample-config.json | 6 ++- views/default-min.handlebars | 2 +- views/default-mobile-min.handlebars | 2 +- views/default.handlebars | 6 +-- 6 files changed, 51 insertions(+), 27 deletions(-) diff --git a/meshrelay.js b/meshrelay.js index c8885f24..a647725e 100644 --- a/meshrelay.js +++ b/meshrelay.js @@ -166,24 +166,36 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie // Setup session recording var sessionUser = user; if (sessionUser == null) { sessionUser = obj.peer.user; } - if (domain.sessionrecording) { - try { parent.parent.fs.mkdirSync(parent.parent.recordpath); } catch (e) { } - var recFilename = 'relaysession' + ((domain.id == '') ? '' : '-') + domain.id + '-' + Date.now() + '-' + sessionUser.name + '-' + obj.id + '.mcrec' - var recFullFilename = parent.parent.path.join(parent.parent.recordpath, recFilename); + if (domain.sessionrecording == true || ((typeof domain.sessionrecording == 'object') && ((domain.sessionrecording.protocols == null) || (domain.sessionrecording.protocols.indexOf(parseInt(req.query.p)) >= 0)))) { + var recFilename = 'relaysession' + ((domain.id == '') ? '' : '-') + domain.id + '-' + Date.now() + '-' + obj.id + '.mcrec' + var recFullFilename = null; + if (domain.sessionrecording.filepath) { + try { parent.parent.fs.mkdirSync(domain.sessionrecording.filepath); } catch (e) { } + recFullFilename = parent.parent.path.join(domain.sessionrecording.filepath, recFilename); + } else { + try { parent.parent.fs.mkdirSync(parent.parent.recordpath); } catch (e) { } + recFullFilename = parent.parent.path.join(parent.parent.recordpath, recFilename); + } parent.parent.fs.open(recFullFilename, 'w', function (err, fd) { - // Write the recording file header - var firstBlock = Buffer.from(JSON.stringify({ magic: 'MeshCentralRelaySession', ver: 1, userid: sessionUser._id, username: sessionUser.name, sessionid: obj.id, ipaddr1: cleanRemoteAddr(ws._socket.remoteAddress), ipaddr2: cleanRemoteAddr(obj.peer.ws._socket.remoteAddress), time: new Date().toLocaleString() })); - var header = Buffer.alloc(16); // Type (2) + Flags (2) + Size(4) + Time(8) - header.writeInt16BE(1, 0); // Type (1 = Header, 2 = Network Data) - header.writeInt16BE(0, 2); // Flags (1 = Binary, 2 = User) - header.writeInt32BE(firstBlock.length, 4); // Size - header.writeIntBE(ws.time, 10, 6); // Time - var block = Buffer.concat([header, firstBlock]); - parent.parent.fs.write(fd, block, 0, block.length, function (err, bytesWritten, buffer) { - relayinfo.peer1.ws.logfile = ws.logfile = { fd: fd, lock: false }; + if (err != null) { + // Unable to record ws.send('c'); // Send connect to both peers relayinfo.peer1.ws.send('c'); - }); + } else { + // Write the recording file header + var firstBlock = Buffer.from(JSON.stringify({ magic: 'MeshCentralRelaySession', ver: 1, userid: sessionUser._id, username: sessionUser.name, sessionid: obj.id, ipaddr1: cleanRemoteAddr(ws._socket.remoteAddress), ipaddr2: cleanRemoteAddr(obj.peer.ws._socket.remoteAddress), time: new Date().toLocaleString(), protocol: req.query.p, nodeid: req.query.nodeid })); + var header = Buffer.alloc(16); // Type (2) + Flags (2) + Size(4) + Time(8) + header.writeInt16BE(1, 0); // Type (1 = Header, 2 = Network Data) + header.writeInt16BE(0, 2); // Flags (1 = Binary, 2 = User) + header.writeInt32BE(firstBlock.length, 4); // Size + header.writeIntBE(ws.time, 10, 6); // Time + var block = Buffer.concat([header, firstBlock]); + parent.parent.fs.write(fd, block, 0, block.length, function (err, bytesWritten, buffer) { + relayinfo.peer1.ws.logfile = ws.logfile = { fd: fd, lock: false }; + ws.send('c'); // Send connect to both peers + relayinfo.peer1.ws.send('c'); + }); + } }); } else { // Send session start @@ -195,7 +207,11 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie // Log the connection if (sessionUser) { - var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: sessionUser._id, username: sessionUser.name, msg: 'Started relay session \"' + obj.id + '\" from ' + cleanRemoteAddr(obj.peer.ws._socket.remoteAddress) + ' to ' + cleanRemoteAddr(ws._socket.remoteAddress) }; + var msg = 'Started relay session'; + if (req.query.p == 1) { msg = 'Started terminal session'; } + else if (req.query.p == 2) { msg = 'Started desktop session'; } + else if (req.query.p == 5) { msg = 'Started file management session'; } + var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: sessionUser._id, username: sessionUser.name, msg: msg + ' \"' + obj.id + '\" from ' + cleanRemoteAddr(obj.peer.ws._socket.remoteAddress) + ' to ' + cleanRemoteAddr(ws._socket.remoteAddress), protocol: req.query.p, nodeid: req.query.nodeid }; parent.parent.DispatchEvent(['*', user._id], obj, event); } } else { @@ -308,11 +324,15 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie // Log the disconnection if (ws.time) { + var msg = 'Ended relay session'; + if (req.query.p == 1) { msg = 'Ended terminal session'; } + else if (req.query.p == 2) { msg = 'Ended desktop session'; } + else if (req.query.p == 5) { msg = 'Ended file management session'; } if (user) { - var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: user._id, username: parent.users[user._id].name, msg: 'Ended relay session \"' + obj.id + '\" from ' + cleanRemoteAddr(obj.peer.ws._socket.remoteAddress) + ' to ' + cleanRemoteAddr(ws._socket.remoteAddress) + ', ' + Math.floor((Date.now() - ws.time) / 1000) + ' second(s)' }; + var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: user._id, username: parent.users[user._id].name, msg: msg + ' \"' + obj.id + '\" from ' + cleanRemoteAddr(obj.peer.ws._socket.remoteAddress) + ' to ' + cleanRemoteAddr(ws._socket.remoteAddress) + ', ' + Math.floor((Date.now() - ws.time) / 1000) + ' second(s)', protocol: req.query.p, nodeid: req.query.nodeid }; parent.parent.DispatchEvent(['*', user._id], obj, event); } else if (peer.user) { - var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: peer.user._id, username: parent.users[peer.user._id].name, msg: 'Ended relay session \"' + obj.id + '\" from ' + cleanRemoteAddr(obj.peer.ws._socket.remoteAddress) + ' to ' + cleanRemoteAddr(ws._socket.remoteAddress) + ', ' + Math.floor((Date.now() - ws.time) / 1000) + ' second(s)' }; + var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: peer.user._id, username: parent.users[peer.user._id].name, msg: msg + ' \"' + obj.id + '\" from ' + cleanRemoteAddr(obj.peer.ws._socket.remoteAddress) + ' to ' + cleanRemoteAddr(ws._socket.remoteAddress) + ', ' + Math.floor((Date.now() - ws.time) / 1000) + ' second(s)', protocol: req.query.p, nodeid: req.query.nodeid }; parent.parent.DispatchEvent(['*', peer.user._id], obj, event); } } @@ -422,7 +442,7 @@ about this recording. It looks something like this: } The rest of the data blocks are all network traffic that was relayed thru the server. They are of TYPE 2 and have -a given size and timestamp. When looking at network traffic the flags are imporant. +a given size and timestamp. When looking at network traffic the flags are important: - If traffic has the first (0x0001) flag set, the data is binary otherwise it's a string. - If the traffic has the second (0x0002) flag set, traffic is coming from the user's browser, if not, it's coming from the MeshAgent. diff --git a/public/scripts/agent-redir-ws-0.1.0.js b/public/scripts/agent-redir-ws-0.1.0.js index 56d55d27..1518c78d 100644 --- a/public/scripts/agent-redir-ws-0.1.0.js +++ b/public/scripts/agent-redir-ws-0.1.0.js @@ -35,7 +35,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort, au //obj.debug = function (msg) { console.log(msg); } obj.Start = function (nodeid) { - var url2, url = window.location.protocol.replace("http", "ws") + "//" + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + "/meshrelay.ashx?browser=1&id=" + obj.tunnelid; + var url2, url = window.location.protocol.replace("http", "ws") + "//" + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + "/meshrelay.ashx?browser=1&p=" + obj.protocol + "&nodeid=" + nodeid + "&id=" + obj.tunnelid; //if (serverPublicNamePort) { url2 = window.location.protocol.replace("http", "ws") + "//" + serverPublicNamePort + "/meshrelay.ashx?id=" + obj.tunnelid; } else { url2 = url; } if ((authCookie != null) && (authCookie != '')) { url += '&auth=' + authCookie; } obj.nodeid = nodeid; @@ -48,7 +48,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort, au obj.socket.onclose = obj.xxOnSocketClosed; obj.xxStateChange(1); //obj.meshserver.send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: url2 }); - obj.meshserver.send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: "*" + domainUrl + "meshrelay.ashx?id=" + obj.tunnelid, usage: obj.protocol }); + obj.meshserver.send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: "*" + domainUrl + "meshrelay.ashx?p=" + obj.protocol + "&nodeid=" + nodeid + "&id=" + obj.tunnelid, usage: obj.protocol }); //obj.debug("Agent Redir Start: " + url); } diff --git a/sample-config.json b/sample-config.json index e436f8b6..cdf0b427 100644 --- a/sample-config.json +++ b/sample-config.json @@ -101,7 +101,11 @@ }, "_yubikey": { "id": "0000", "secret": "xxxxxxxxxxxxxxxxxxxxx", "_proxy": "http://myproxy.domain.com:80" }, "_httpheaders": { "Strict-Transport-Security": "max-age=360000" }, - "_agentConfig": [ "webSocketMaskOverride=1" ] + "_agentConfig": [ "webSocketMaskOverride=1" ], + "_SessionRecording": { + "_filepath": "C:\\temp", + "protocols": [ 1, 2 ] + } }, "customer1": { "DNS": "customer1.myserver.com", diff --git a/views/default-min.handlebars b/views/default-min.handlebars index 565868eb..f43a9fc3 100644 --- a/views/default-min.handlebars +++ b/views/default-min.handlebars @@ -1 +1 @@ - {{{title}}}
{{{title}}}
{{{title2}}}

{{{logoutControl}}}

 

\ No newline at end of file + {{{title}}}
{{{title}}}
{{{title2}}}

{{{logoutControl}}}

 

\ No newline at end of file diff --git a/views/default-mobile-min.handlebars b/views/default-mobile-min.handlebars index 2cce30c8..e51f1360 100644 --- a/views/default-mobile-min.handlebars +++ b/views/default-mobile-min.handlebars @@ -1 +1 @@ - {{{title}}}
{{{title}}}
{{{title2}}}
\ No newline at end of file + {{{title}}}
{{{title}}}
{{{title2}}}
\ No newline at end of file diff --git a/views/default.handlebars b/views/default.handlebars index cc9ec051..8c22ee46 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -5992,7 +5992,6 @@ var icon = 'si3'; if (event.etype == 'user') icon = 'm2'; if (event.etype == 'server') icon = 'si3'; - if (event.etype == 'relay') icon = 'relayIcon16'; var msg = EscapeHtml(event.msg).split('(R)').join('®'); if (event.username) { @@ -6002,6 +6001,7 @@ msg = EscapeHtml(event.username) + ' → ' + msg; } } + if (event.etype == 'relay' || event.action == 'relaylog') icon = 'relayIcon16'; x += '
 ' + printTime(time) + ' - ' + msg + ' '; } } @@ -7379,7 +7379,6 @@ var icon = 'si3'; if (event.etype == 'user') icon = 'm2'; if (event.etype == 'server') icon = 'si3'; - if (event.etype == 'relay') icon = 'relayIcon16'; var msg = EscapeHtml(event.msg).split('(R)').join('®'); if (event.nodeid) { @@ -7396,6 +7395,7 @@ msg = EscapeHtml(event.username) + ' → ' + msg; } } + if (event.etype == 'relay' || event.action == 'relaylog') icon = 'relayIcon16'; x += '
 ' + printTime(time) + ' - ' + msg + ' '; } } @@ -8085,7 +8085,6 @@ var icon = 'si3'; if (event.etype == 'user') icon = 'm2'; if (event.etype == 'server') icon = 'si3'; - if (event.etype == 'relay') icon = 'relayIcon16'; var msg = EscapeHtml(event.msg).split('(R)').join('®'); if (event.nodeid) { @@ -8102,6 +8101,7 @@ msg = EscapeHtml(event.username) + ' → ' + msg; } } + if (event.etype == 'relay' || event.action == 'relaylog') icon = 'relayIcon16'; x += '
 ' + printTime(time) + ' - ' + msg + ' '; } }