Added server tracing dialog in web app.

This commit is contained in:
Ylian Saint-Hilaire 2019-08-22 15:31:39 -07:00
parent 57c3b61e37
commit de26e8370d
14 changed files with 317 additions and 198 deletions

View File

@ -45,8 +45,8 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Disconnect this agent // Disconnect this agent
obj.close = function (arg) { obj.close = function (arg) {
obj.authenticated = -1; obj.authenticated = -1;
if ((arg == 1) || (arg == null)) { try { ws.close(); if (obj.nodeid != null) { parent.parent.debug(1, 'Soft disconnect ' + obj.nodeid + ' (' + obj.remoteaddrport + ')'); } } catch (e) { console.log(e); } } // Soft close, close the websocket if ((arg == 1) || (arg == null)) { try { ws.close(); if (obj.nodeid != null) { parent.parent.debug('agent', 'Soft disconnect ' + obj.nodeid + ' (' + obj.remoteaddrport + ')'); } } catch (e) { console.log(e); } } // Soft close, close the websocket
if (arg == 2) { try { ws._socket._parent.end(); if (obj.nodeid != null) { parent.parent.debug(1, 'Hard disconnect ' + obj.nodeid + ' (' + obj.remoteaddrport + ')'); } } catch (e) { console.log(e); } } // Hard close, close the TCP socket if (arg == 2) { try { ws._socket._parent.end(); if (obj.nodeid != null) { parent.parent.debug('agent', 'Hard disconnect ' + obj.nodeid + ' (' + obj.remoteaddrport + ')'); } } catch (e) { console.log(e); } } // Hard close, close the TCP socket
// If arg == 3, don't communicate with this agent anymore, but don't disconnect (Duplicate agent). // If arg == 3, don't communicate with this agent anymore, but don't disconnect (Duplicate agent).
// Remove this agent from the webserver list // Remove this agent from the webserver list
@ -166,11 +166,11 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Clear the core // Clear the core
obj.sendBinary(common.ShortToStr(10) + common.ShortToStr(0)); // MeshCommand_CoreModule, ask mesh agent to clear the core obj.sendBinary(common.ShortToStr(10) + common.ShortToStr(0)); // MeshCommand_CoreModule, ask mesh agent to clear the core
parent.agentStats.clearingCoreCount++; parent.agentStats.clearingCoreCount++;
parent.parent.debug(1, 'Clearing core'); parent.parent.debug('agent', 'Clearing core');
} else { } else {
// Update new core // Update new core
//obj.sendBinary(common.ShortToStr(10) + common.ShortToStr(0) + meshcorehash + parent.parent.defaultMeshCores[corename]); // MeshCommand_CoreModule, start core update //obj.sendBinary(common.ShortToStr(10) + common.ShortToStr(0) + meshcorehash + parent.parent.defaultMeshCores[corename]); // MeshCommand_CoreModule, start core update
//parent.parent.debug(1, 'Updating code ' + corename); //parent.parent.debug('agent', 'Updating code ' + corename);
// Update new core with task limiting so not to flood the server. This is a high priority task. // Update new core with task limiting so not to flood the server. This is a high priority task.
obj.agentCoreUpdatePending = true; obj.agentCoreUpdatePending = true;
@ -180,7 +180,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
delete obj.agentCoreUpdatePending; delete obj.agentCoreUpdatePending;
obj.sendBinary(common.ShortToStr(10) + common.ShortToStr(0) + argument.hash + argument.core, function () { parent.parent.taskLimiter.completed(taskid); }); // MeshCommand_CoreModule, start core update obj.sendBinary(common.ShortToStr(10) + common.ShortToStr(0) + argument.hash + argument.core, function () { parent.parent.taskLimiter.completed(taskid); }); // MeshCommand_CoreModule, start core update
parent.agentStats.updatingCoreCount++; parent.agentStats.updatingCoreCount++;
parent.parent.debug(1, 'Updating core ' + argument.name); parent.parent.debug('agent', 'Updating core ' + argument.name);
agentCoreIsStable(); agentCoreIsStable();
} else { } else {
// This agent is probably disconnected, nothing to do. // This agent is probably disconnected, nothing to do.
@ -228,7 +228,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Mesh agent update required, do it using task limiter so not to flood the network. Medium priority task. // Mesh agent update required, do it using task limiter so not to flood the network. Medium priority task.
parent.parent.taskLimiter.launch(function (argument, taskid, taskLimiterQueue) { parent.parent.taskLimiter.launch(function (argument, taskid, taskLimiterQueue) {
if (obj.authenticated != 2) { parent.parent.taskLimiter.completed(taskid); return; } // If agent disconnection, complete and exit now. if (obj.authenticated != 2) { parent.parent.taskLimiter.completed(taskid); return; } // If agent disconnection, complete and exit now.
if (obj.nodeid != null) { parent.parent.debug(1, 'Agent update required, NodeID=0x' + obj.nodeid.substring(0, 16) + ', ' + obj.agentExeInfo.desc); } if (obj.nodeid != null) { parent.parent.debug('agent', 'Agent update required, NodeID=0x' + obj.nodeid.substring(0, 16) + ', ' + obj.agentExeInfo.desc); }
parent.agentStats.agentBinaryUpdate++; parent.agentStats.agentBinaryUpdate++;
if (obj.agentExeInfo.data == null) { if (obj.agentExeInfo.data == null) {
// Read the agent from disk // Read the agent from disk
@ -448,7 +448,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
//console.log('MeshID', obj.meshid); //console.log('MeshID', obj.meshid);
obj.agentInfo.capabilities = common.ReadInt(msg, 66); obj.agentInfo.capabilities = common.ReadInt(msg, 66);
const computerNameLen = common.ReadShort(msg, 70); const computerNameLen = common.ReadShort(msg, 70);
obj.agentInfo.computerName = msg.substring(72, 72 + computerNameLen); obj.agentInfo.computerName = Buffer.from(msg.substring(72, 72 + computerNameLen), 'binary').toString('utf8');
obj.dbMeshKey = 'mesh/' + domain.id + '/' + obj.meshid; obj.dbMeshKey = 'mesh/' + domain.id + '/' + obj.meshid;
completeAgentConnection(); completeAgentConnection();
} else if (cmd == 4) { } else if (cmd == 4) {
@ -471,7 +471,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
if (obj.nodeid != null) { if (obj.nodeid != null) {
const agentId = (obj.agentInfo && obj.agentInfo.agentId) ? obj.agentInfo.agentId : 'Unknown'; const agentId = (obj.agentInfo && obj.agentInfo.agentId) ? obj.agentInfo.agentId : 'Unknown';
//console.log('Agent disconnect ' + obj.nodeid + ' (' + obj.remoteaddrport + ') id=' + agentId); //console.log('Agent disconnect ' + obj.nodeid + ' (' + obj.remoteaddrport + ') id=' + agentId);
parent.parent.debug(1, 'Agent disconnect ' + obj.nodeid + ' (' + obj.remoteaddrport + ') id=' + agentId); parent.parent.debug('agent', 'Agent disconnect ' + obj.nodeid + ' (' + obj.remoteaddrport + ') id=' + agentId);
// Log the agent disconnection // Log the agent disconnection
if (parent.wsagentsDisconnections[obj.nodeid] == null) { if (parent.wsagentsDisconnections[obj.nodeid] == null) {
@ -765,7 +765,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Close the duplicate agent // Close the duplicate agent
parent.agentStats.duplicateAgentCount++; parent.agentStats.duplicateAgentCount++;
if (obj.nodeid != null) { parent.parent.debug(1, 'Duplicate agent ' + obj.nodeid + ' (' + obj.remoteaddrport + ')'); } if (obj.nodeid != null) { parent.parent.debug('agent', 'Duplicate agent ' + obj.nodeid + ' (' + obj.remoteaddrport + ')'); }
dupAgent.close(3); dupAgent.close(3);
} else { } else {
// Indicate the agent is connected // Indicate the agent is connected
@ -1034,7 +1034,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
delete obj.receivedCommands; delete obj.receivedCommands;
if (obj.unauthsign) delete obj.unauthsign; if (obj.unauthsign) delete obj.unauthsign;
parent.agentStats.verifiedAgentConnectionCount++; parent.agentStats.verifiedAgentConnectionCount++;
parent.parent.debug(1, 'Verified agent connection to ' + obj.nodeid + ' (' + obj.remoteaddrport + ').'); parent.parent.debug('agent', 'Verified agent connection to ' + obj.nodeid + ' (' + obj.remoteaddrport + ').');
obj.authenticated = 1; obj.authenticated = 1;
return true; return true;
} }

View File

@ -44,7 +44,8 @@ function CreateMeshCentralServer(config, args) {
obj.certificates = null; obj.certificates = null;
obj.connectivityByNode = {}; // This object keeps a list of all connected CIRA and agents, by nodeid->value (value: 1 = Agent, 2 = CIRA, 4 = AmtDirect) obj.connectivityByNode = {}; // This object keeps a list of all connected CIRA and agents, by nodeid->value (value: 1 = Agent, 2 = CIRA, 4 = AmtDirect)
obj.peerConnectivityByNode = {}; // This object keeps a list of all connected CIRA and agents of peers, by serverid->nodeid->value (value: 1 = Agent, 2 = CIRA, 4 = AmtDirect) obj.peerConnectivityByNode = {}; // This object keeps a list of all connected CIRA and agents of peers, by serverid->nodeid->value (value: 1 = Agent, 2 = CIRA, 4 = AmtDirect)
obj.debugLevel = 0; obj.debugSources = [];
obj.debugRemoteSources = [];
obj.config = config; // Configuration file obj.config = config; // Configuration file
obj.dbconfig = {}; // Persistance values, loaded from database obj.dbconfig = {}; // Persistance values, loaded from database
obj.certificateOperations = null; obj.certificateOperations = null;
@ -108,7 +109,7 @@ function CreateMeshCentralServer(config, args) {
try { require('./pass').hash('test', function () { }, 0); } catch (e) { console.log('Old version of node, must upgrade.'); return; } // TODO: Not sure if this test works or not. try { require('./pass').hash('test', function () { }, 0); } catch (e) { console.log('Old version of node, must upgrade.'); return; } // TODO: Not sure if this test works or not.
// Check for invalid arguments // Check for invalid arguments
var validArguments = ['_', 'notls', 'user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'cert', 'mpscert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'clearpower', 'showiplocations', 'help', 'exactports', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpsdebug', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbexportmin', 'dbimport', 'dbmerge', 'dbencryptkey', 'selfupdate', 'tlsoffload', 'userallowedip', 'userblockedip', 'swarmallowedip', 'agentallowedip', 'agentblockedip', 'fastcert', 'swarmport', 'swarmdebug', 'logintoken', 'logintokenkey', 'logintokengen', 'logintokengen', 'mailtokengen', 'admin', 'unadmin', 'sessionkey', 'sessiontime', 'minify', 'minifycore', 'dblistconfigfiles', 'dbshowconfigfile', 'dbpushconfigfiles', 'dbpullconfigfiles', 'dbdeleteconfigfiles', 'configkey', 'loadconfigfromdb', 'npmpath', 'memorytracking', 'serverid']; var validArguments = ['_', 'notls', 'user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'cert', 'mpscert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'clearpower', 'showiplocations', 'help', 'exactports', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'remotedebug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbexportmin', 'dbimport', 'dbmerge', 'dbencryptkey', 'selfupdate', 'tlsoffload', 'userallowedip', 'userblockedip', 'swarmallowedip', 'agentallowedip', 'agentblockedip', 'fastcert', 'swarmport', 'logintoken', 'logintokenkey', 'logintokengen', 'logintokengen', 'mailtokengen', 'admin', 'unadmin', 'sessionkey', 'sessiontime', 'minify', 'minifycore', 'dblistconfigfiles', 'dbshowconfigfile', 'dbpushconfigfiles', 'dbpullconfigfiles', 'dbdeleteconfigfiles', 'configkey', 'loadconfigfromdb', 'npmpath', 'memorytracking', 'serverid'];
for (var arg in obj.args) { obj.args[arg.toLocaleLowerCase()] = obj.args[arg]; if (validArguments.indexOf(arg.toLocaleLowerCase()) == -1) { console.log('Invalid argument "' + arg + '", use --help.'); return; } } for (var arg in obj.args) { obj.args[arg.toLocaleLowerCase()] = obj.args[arg]; if (validArguments.indexOf(arg.toLocaleLowerCase()) == -1) { console.log('Invalid argument "' + arg + '", use --help.'); return; } }
if (obj.args.mongodb == true) { console.log('Must specify: --mongodb [connectionstring] \r\nSee https://docs.mongodb.com/manual/reference/connection-string/ for MongoDB connection string.'); return; } if (obj.args.mongodb == true) { console.log('Must specify: --mongodb [connectionstring] \r\nSee https://docs.mongodb.com/manual/reference/connection-string/ for MongoDB connection string.'); return; }
for (i in obj.config.settings) { obj.args[i] = obj.config.settings[i]; } // Place all settings into arguments, arguments have already been placed into settings so arguments take precedence. for (i in obj.config.settings) { obj.args[i] = obj.config.settings[i]; } // Place all settings into arguments, arguments have already been placed into settings so arguments take precedence.
@ -257,8 +258,17 @@ function CreateMeshCentralServer(config, args) {
if (typeof obj.args.agentallowedip == 'string') { if (obj.args.agentallowedip == '') { obj.args.agentallowedip = null; } else { obj.args.agentallowedip = obj.args.agentallowedip.split(','); } } if (typeof obj.args.agentallowedip == 'string') { if (obj.args.agentallowedip == '') { obj.args.agentallowedip = null; } else { obj.args.agentallowedip = obj.args.agentallowedip.split(','); } }
if (typeof obj.args.agentblockedip == 'string') { if (obj.args.agentblockedip == '') { obj.args.agentblockedip = null; } else { obj.args.agentblockedip = obj.args.agentblockedip.split(','); } } if (typeof obj.args.agentblockedip == 'string') { if (obj.args.agentblockedip == '') { obj.args.agentblockedip = null; } else { obj.args.agentblockedip = obj.args.agentblockedip.split(','); } }
if (typeof obj.args.swarmallowedip == 'string') { if (obj.args.swarmallowedip == '') { obj.args.swarmallowedip = null; } else { obj.args.swarmallowedip = obj.args.swarmallowedip.split(','); } } if (typeof obj.args.swarmallowedip == 'string') { if (obj.args.swarmallowedip == '') { obj.args.swarmallowedip = null; } else { obj.args.swarmallowedip = obj.args.swarmallowedip.split(','); } }
if (typeof obj.args.debug == 'number') obj.debugLevel = obj.args.debug;
if (obj.args.debug == true) obj.debugLevel = 1; // Local console tracing
if (typeof obj.args.debug == 'string') { obj.debugSources = obj.args.debug.toLowerCase().split(','); }
else if (typeof obj.args.debug == 'object') { obj.debugSources = obj.args.debug; }
else if (obj.args.debug === true) { obj.debugSources = '*'; }
// Remote web application tracing
if (typeof obj.args.remotedebug == 'string') { obj.debugRemoteSources = obj.args.remotedebug.toLowerCase().split(','); }
else if (typeof obj.args.remotedebug == 'object') { obj.debugRemoteSources = obj.args.remotedebug; }
else if (obj.args.remotedebug === true) { obj.debugRemoteSources = '*'; }
require('./db.js').CreateDB(obj, require('./db.js').CreateDB(obj,
function (db) { function (db) {
obj.db = db; obj.db = db;
@ -896,7 +906,7 @@ function CreateMeshCentralServer(config, args) {
obj.DispatchEvent(['*'], obj, { action: 'servertimelinestats', data: data }); // Event the server stats obj.DispatchEvent(['*'], obj, { action: 'servertimelinestats', data: data }); // Event the server stats
}, 300000); }, 300000);
//obj.debug(1, 'Server started'); obj.debug('main', 'Server started');
if (obj.args.nousers == true) { obj.updateServerState('nousers', '1'); } if (obj.args.nousers == true) { obj.updateServerState('nousers', '1'); }
obj.updateServerState('state', 'running'); obj.updateServerState('state', 'running');
@ -940,7 +950,7 @@ function CreateMeshCentralServer(config, args) {
// Set all nodes to power state of unknown (0) // Set all nodes to power state of unknown (0)
obj.db.storePowerEvent({ time: new Date(), nodeid: '*', power: 0, s: 2 }, obj.multiServer, function () { // s:2 indicates that the server is shutting down. obj.db.storePowerEvent({ time: new Date(), nodeid: '*', power: 0, s: 2 }, obj.multiServer, function () { // s:2 indicates that the server is shutting down.
if (restoreFile) { if (restoreFile) {
obj.debug(1, 'Server stopped, updating settings: ' + restoreFile); obj.debug('main', 'Server stopped, updating settings: ' + restoreFile);
console.log('Updating settings folder...'); console.log('Updating settings folder...');
var yauzl = require("yauzl"); var yauzl = require("yauzl");
@ -966,7 +976,7 @@ function CreateMeshCentralServer(config, args) {
zipfile.on("end", function () { setTimeout(function () { obj.fs.unlinkSync(restoreFile); process.exit(123); }); }); zipfile.on("end", function () { setTimeout(function () { obj.fs.unlinkSync(restoreFile); process.exit(123); }); });
}); });
} else { } else {
obj.debug(1, 'Server stopped'); obj.debug('main', 'Server stopped');
process.exit(0); process.exit(0);
} }
}); });
@ -977,26 +987,26 @@ function CreateMeshCentralServer(config, args) {
// Event Dispatch // Event Dispatch
obj.AddEventDispatch = function (ids, target) { obj.AddEventDispatch = function (ids, target) {
obj.debug(3, 'AddEventDispatch', ids); obj.debug('dispatch', 'AddEventDispatch', ids);
for (var i in ids) { var id = ids[i]; if (!obj.eventsDispatch[id]) { obj.eventsDispatch[id] = [target]; } else { obj.eventsDispatch[id].push(target); } } for (var i in ids) { var id = ids[i]; if (!obj.eventsDispatch[id]) { obj.eventsDispatch[id] = [target]; } else { obj.eventsDispatch[id].push(target); } }
}; };
obj.RemoveEventDispatch = function (ids, target) { obj.RemoveEventDispatch = function (ids, target) {
obj.debug(3, 'RemoveEventDispatch', id); obj.debug('dispatch', 'RemoveEventDispatch', id);
for (var i in ids) { var id = ids[i]; if (obj.eventsDispatch[id]) { var j = obj.eventsDispatch[id].indexOf(target); if (j >= 0) { if (obj.eventsDispatch[id].length == 1) { delete obj.eventsDispatch[id]; } else { obj.eventsDispatch[id].splice(j, 1); } } } } for (var i in ids) { var id = ids[i]; if (obj.eventsDispatch[id]) { var j = obj.eventsDispatch[id].indexOf(target); if (j >= 0) { if (obj.eventsDispatch[id].length == 1) { delete obj.eventsDispatch[id]; } else { obj.eventsDispatch[id].splice(j, 1); } } } }
}; };
obj.RemoveEventDispatchId = function (id) { obj.RemoveEventDispatchId = function (id) {
obj.debug(3, 'RemoveEventDispatchId', id); obj.debug('dispatch', 'RemoveEventDispatchId', id);
if (obj.eventsDispatch[id] != null) { delete obj.eventsDispatch[id]; } if (obj.eventsDispatch[id] != null) { delete obj.eventsDispatch[id]; }
}; };
obj.RemoveAllEventDispatch = function (target) { obj.RemoveAllEventDispatch = function (target) {
obj.debug(3, 'RemoveAllEventDispatch'); obj.debug('dispatch', 'RemoveAllEventDispatch');
for (var i in obj.eventsDispatch) { var j = obj.eventsDispatch[i].indexOf(target); if (j >= 0) { if (obj.eventsDispatch[i].length == 1) { delete obj.eventsDispatch[i]; } else { obj.eventsDispatch[i].splice(j, 1); } } } for (var i in obj.eventsDispatch) { var j = obj.eventsDispatch[i].indexOf(target); if (j >= 0) { if (obj.eventsDispatch[i].length == 1) { delete obj.eventsDispatch[i]; } else { obj.eventsDispatch[i].splice(j, 1); } } }
}; };
obj.DispatchEvent = function (ids, source, event, fromPeerServer) { obj.DispatchEvent = function (ids, source, event, fromPeerServer) {
// If the database is not setup, exit now. // If the database is not setup, exit now.
if (!obj.db) return; if (!obj.db) return;
obj.debug(3, 'DispatchEvent', ids); obj.debug('dispatch', 'DispatchEvent', ids);
if ((typeof event == 'object') && (!event.nolog)) { if ((typeof event == 'object') && (!event.nolog)) {
event.time = new Date(); event.time = new Date();
// The event we store is going to skip some of the fields so we don't store too much stuff in the database. // The event we store is going to skip some of the fields so we don't store too much stuff in the database.
@ -1340,7 +1350,7 @@ function CreateMeshCentralServer(config, args) {
obj.defaultMeshCores[i] = [obj.common.IntToStr(0), ...modulesAdd[i], meshCore].join(''); obj.defaultMeshCores[i] = [obj.common.IntToStr(0), ...modulesAdd[i], meshCore].join('');
} }
obj.defaultMeshCoresHash[i] = obj.crypto.createHash('sha384').update(obj.defaultMeshCores[i]).digest("binary"); obj.defaultMeshCoresHash[i] = obj.crypto.createHash('sha384').update(obj.defaultMeshCores[i]).digest("binary");
obj.debug(1, 'Core module ' + i + ' is ' + obj.defaultMeshCores[i].length + ' bytes.'); obj.debug('main', 'Core module ' + i + ' is ' + obj.defaultMeshCores[i].length + ' bytes.');
//console.log('Core module ' + i + ' is ' + obj.defaultMeshCores[i].length + ' bytes.'); // DEBUG, Print the core size //console.log('Core module ' + i + ' is ' + obj.defaultMeshCores[i].length + ' bytes.'); // DEBUG, Print the core size
//obj.fs.writeFile("C:\\temp\\" + i + ".js", obj.defaultMeshCores[i].substring(4)); // DEBUG, Write the core to file //obj.fs.writeFile("C:\\temp\\" + i + ".js", obj.defaultMeshCores[i].substring(4)); // DEBUG, Write the core to file
} }
@ -1583,19 +1593,19 @@ function CreateMeshCentralServer(config, args) {
const decipher = obj.crypto.createDecipheriv('aes-256-gcm', key.slice(0, 32), cookie.slice(0, 12)); const decipher = obj.crypto.createDecipheriv('aes-256-gcm', key.slice(0, 32), cookie.slice(0, 12));
decipher.setAuthTag(cookie.slice(12, 16)); decipher.setAuthTag(cookie.slice(12, 16));
const o = JSON.parse(decipher.update(cookie.slice(28), 'binary', 'utf8') + decipher.final('utf8')); const o = JSON.parse(decipher.update(cookie.slice(28), 'binary', 'utf8') + decipher.final('utf8'));
if ((o.time == null) || (o.time == null) || (typeof o.time != 'number')) { obj.debug(1, 'ERR: Bad cookie due to invalid time'); return null; } if ((o.time == null) || (o.time == null) || (typeof o.time != 'number')) { obj.debug('cookie', 'ERR: Bad cookie due to invalid time'); return null; }
o.time = o.time * 1000; // Decode the cookie creation time o.time = o.time * 1000; // Decode the cookie creation time
o.dtime = Date.now() - o.time; // Decode how long ago the cookie was created (in milliseconds) o.dtime = Date.now() - o.time; // Decode how long ago the cookie was created (in milliseconds)
if ((o.expire) == null || (typeof o.expire != 'number')) { if ((o.expire) == null || (typeof o.expire != 'number')) {
// Use a fixed cookie expire time // Use a fixed cookie expire time
if (timeout == null) { timeout = 2; } if (timeout == null) { timeout = 2; }
if ((o.dtime > (timeout * 60000)) || (o.dtime < -30000)) { obj.debug(1, 'ERR: Bad cookie due to timeout'); return null; } // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right) if ((o.dtime > (timeout * 60000)) || (o.dtime < -30000)) { obj.debug('cookie', 'ERR: Bad cookie due to timeout'); return null; } // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right)
} else { } else {
// An expire time is included in the cookie (in minutes), use this. // An expire time is included in the cookie (in minutes), use this.
if ((o.expire !== 0) && ((o.dtime > (o.expire * 60000)) || (o.dtime < -30000))) { obj.debug(1, 'ERR: Bad cookie due to timeout'); return null; } // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right) if ((o.expire !== 0) && ((o.dtime > (o.expire * 60000)) || (o.dtime < -30000))) { obj.debug('cookie', 'ERR: Bad cookie due to timeout'); return null; } // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right)
} }
return o; return o;
} catch (ex) { obj.debug(1, 'ERR: Bad AESGCM cookie due to exception: ' + ex); return null; } } catch (ex) { obj.debug('cookie', 'ERR: Bad AESGCM cookie due to exception: ' + ex); return null; }
}; };
// Decode a cookie back into an object using a key using AES256 / HMAC-SHA386. Return null if it's not a valid cookie. (key must be 80 bytes or more) // Decode a cookie back into an object using a key using AES256 / HMAC-SHA386. Return null if it's not a valid cookie. (key must be 80 bytes or more)
@ -1611,28 +1621,38 @@ function CreateMeshCentralServer(config, args) {
hmac.update(rawmsg.slice(48)); hmac.update(rawmsg.slice(48));
if (Buffer.compare(hmac.digest(), Buffer.from(rawmsg.slice(0, 48))) == false) { return null; } if (Buffer.compare(hmac.digest(), Buffer.from(rawmsg.slice(0, 48))) == false) { return null; }
const o = JSON.parse(rawmsg.slice(48).toString('utf8')); const o = JSON.parse(rawmsg.slice(48).toString('utf8'));
if ((o.time == null) || (o.time == null) || (typeof o.time != 'number')) { obj.debug(1, 'ERR: Bad cookie due to invalid time'); return null; } if ((o.time == null) || (o.time == null) || (typeof o.time != 'number')) { obj.debug('cookie', 'ERR: Bad cookie due to invalid time'); return null; }
o.time = o.time * 1000; // Decode the cookie creation time o.time = o.time * 1000; // Decode the cookie creation time
o.dtime = Date.now() - o.time; // Decode how long ago the cookie was created (in milliseconds) o.dtime = Date.now() - o.time; // Decode how long ago the cookie was created (in milliseconds)
if ((o.expire) == null || (typeof o.expire != 'number')) { if ((o.expire) == null || (typeof o.expire != 'number')) {
// Use a fixed cookie expire time // Use a fixed cookie expire time
if (timeout == null) { timeout = 2; } if (timeout == null) { timeout = 2; }
if ((o.dtime > (timeout * 60000)) || (o.dtime < -30000)) { obj.debug(1, 'ERR: Bad cookie due to timeout'); return null; } // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right) if ((o.dtime > (timeout * 60000)) || (o.dtime < -30000)) { obj.debug('cookie', 'ERR: Bad cookie due to timeout'); return null; } // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right)
} else { } else {
// An expire time is included in the cookie (in minutes), use this. // An expire time is included in the cookie (in minutes), use this.
if ((o.expire !== 0) && ((o.dtime > (o.expire * 60000)) || (o.dtime < -30000))) { obj.debug(1, 'ERR: Bad cookie due to timeout'); return null; } // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right) if ((o.expire !== 0) && ((o.dtime > (o.expire * 60000)) || (o.dtime < -30000))) { obj.debug('cookie', 'ERR: Bad cookie due to timeout'); return null; } // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right)
} }
return o; return o;
} catch (ex) { obj.debug(1, 'ERR: Bad AESSHA cookie due to exception: ' + ex); return null; } } catch (ex) { obj.debug('cookie', 'ERR: Bad AESSHA cookie due to exception: ' + ex); return null; }
}; };
// Debug // Debug
obj.debug = function (lvl) { obj.debug = function (source, ...args) {
if (lvl > obj.debugLevel) return; // Send event to console
if (arguments.length == 2) { console.log(arguments[1]); } if ((obj.debugSources != null) && ((obj.debugSources == '*') || (obj.debugSources.indexOf(source) >= 0))) { console.log(source.toUpperCase() + ':', ...args); }
else if (arguments.length == 3) { console.log(arguments[1], arguments[2]); }
else if (arguments.length == 4) { console.log(arguments[1], arguments[2], arguments[3]); } // Send the event to logged in administrators
else if (arguments.length == 5) { console.log(arguments[1], arguments[2], arguments[3], arguments[4]); } if ((obj.debugRemoteSources != null) && ((obj.debugRemoteSources == '*') || (obj.debugRemoteSources.indexOf(source) >= 0))) {
for (var sessionid in obj.webserver.wssessions2) {
var ws = obj.webserver.wssessions2[sessionid];
if ((ws != null) && (ws.userid != null)) {
var user = obj.webserver.users[ws.userid];
if ((user != null) && (user.siteadmin == 4294967295)) {
try { ws.send(JSON.stringify({ action: 'trace', source: source, args: args, time: Date.now() })); } catch (ex) { }
}
}
}
}
}; };
// Update server state. Writes a server state file. // Update server state. Writes a server state file.

View File

@ -48,8 +48,8 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
// Disconnect this agent // Disconnect this agent
obj.close = function (arg) { obj.close = function (arg) {
if ((arg == 1) || (arg == null)) { try { ws.close(); parent.parent.debug(1, 'Relay: Soft disconnect (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); } catch (e) { console.log(e); } } // Soft close, close the websocket if ((arg == 1) || (arg == null)) { try { ws.close(); parent.parent.debug('relay', 'Relay: Soft disconnect (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); } catch (e) { console.log(e); } } // Soft close, close the websocket
if (arg == 2) { try { ws._socket._parent.end(); parent.parent.debug(1, 'Relay: Hard disconnect (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); } catch (e) { console.log(e); } } // Hard close, close the TCP socket if (arg == 2) { try { ws._socket._parent.end(); parent.parent.debug('relay', 'Relay: Hard disconnect (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); } catch (e) { console.log(e); } } // Hard close, close the TCP socket
// Aggressive cleanup // Aggressive cleanup
delete obj.id; delete obj.id;
@ -143,7 +143,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
// Check that at least one connection is authenticated // Check that at least one connection is authenticated
if ((obj.authenticated != true) && (relayinfo.peer1.authenticated != true)) { if ((obj.authenticated != true) && (relayinfo.peer1.authenticated != true)) {
ws.close(); ws.close();
parent.parent.debug(1, 'Relay without-auth: ' + obj.id + ' (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); parent.parent.debug('relay', 'Relay without-auth: ' + obj.id + ' (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')');
delete obj.id; delete obj.id;
delete obj.ws; delete obj.ws;
delete obj.peer; delete obj.peer;
@ -200,7 +200,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
try { relayinfo.peer1.ws.send('c'); } catch (ex) { } try { relayinfo.peer1.ws.send('c'); } catch (ex) { }
} }
parent.parent.debug(1, 'Relay connected: ' + obj.id + ' (' + cleanRemoteAddr(ws._socket.remoteAddress) + ' --> ' + cleanRemoteAddr(obj.peer.ws._socket.remoteAddress) + ')'); parent.parent.debug('relay', 'Relay connected: ' + obj.id + ' (' + cleanRemoteAddr(ws._socket.remoteAddress) + ' --> ' + cleanRemoteAddr(obj.peer.ws._socket.remoteAddress) + ')');
// Log the connection // Log the connection
if (sessionUser != null) { if (sessionUser != null) {
@ -214,7 +214,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
} else { } else {
// Connected already, drop (TODO: maybe we should re-connect?) // Connected already, drop (TODO: maybe we should re-connect?)
ws.close(); ws.close();
parent.parent.debug(1, 'Relay duplicate: ' + obj.id + ' (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); parent.parent.debug('relay', 'Relay duplicate: ' + obj.id + ' (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')');
delete obj.id; delete obj.id;
delete obj.ws; delete obj.ws;
delete obj.peer; delete obj.peer;
@ -224,7 +224,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
// Wait for other relay connection // Wait for other relay connection
ws._socket.pause(); // Hold traffic until the other connection ws._socket.pause(); // Hold traffic until the other connection
parent.wsrelays[obj.id] = { peer1: obj, state: 1, timeout: setTimeout(function () { closeBothSides(); }, 30000) }; parent.wsrelays[obj.id] = { peer1: obj, state: 1, timeout: setTimeout(function () { closeBothSides(); }, 30000) };
parent.parent.debug(1, 'Relay holding: ' + obj.id + ' (' + cleanRemoteAddr(ws._socket.remoteAddress) + ') ' + (obj.authenticated ? 'Authenticated' : '')); parent.parent.debug('relay', 'Relay holding: ' + obj.id + ' (' + cleanRemoteAddr(ws._socket.remoteAddress) + ') ' + (obj.authenticated ? 'Authenticated' : ''));
// Check if a peer server has this connection // Check if a peer server has this connection
if (parent.parent.multiServer != null) { if (parent.parent.multiServer != null) {
@ -290,7 +290,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
// Disconnect the peer // Disconnect the peer
try { if (peer.relaySessionCounted) { parent.relaySessionCount--; delete peer.relaySessionCounted; } } catch (ex) { console.log(ex); } try { if (peer.relaySessionCounted) { parent.relaySessionCount--; delete peer.relaySessionCounted; } } catch (ex) { console.log(ex); }
parent.parent.debug(1, 'Relay disconnect: ' + obj.id + ' (' + cleanRemoteAddr(ws._socket.remoteAddress) + ' --> ' + cleanRemoteAddr(peer.ws._socket.remoteAddress) + ')'); parent.parent.debug('relay', 'Relay disconnect: ' + obj.id + ' (' + cleanRemoteAddr(ws._socket.remoteAddress) + ' --> ' + cleanRemoteAddr(peer.ws._socket.remoteAddress) + ')');
try { peer.ws.close(); } catch (e) { } // Soft disconnect try { peer.ws.close(); } catch (e) { } // Soft disconnect
try { peer.ws._socket._parent.end(); } catch (e) { } // Hard disconnect try { peer.ws._socket._parent.end(); } catch (e) { } // Hard disconnect
@ -314,7 +314,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
delete peer.ws; delete peer.ws;
delete peer.peer; delete peer.peer;
} else { } else {
parent.parent.debug(1, 'Relay disconnect: ' + obj.id + ' (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); parent.parent.debug('relay', 'Relay disconnect: ' + obj.id + ' (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')');
} }
try { ws.close(); } catch (ex) { } try { ws.close(); } catch (ex) { }
delete parent.wsrelays[obj.id]; delete parent.wsrelays[obj.id];
@ -370,8 +370,8 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
// Send connection request to agent // Send connection request to agent
if (obj.id == undefined) { obj.id = ('' + Math.random()).substring(2); } // If there is no connection id, generate one. if (obj.id == undefined) { obj.id = ('' + Math.random()).substring(2); } // If there is no connection id, generate one.
var command = { nodeid: cookie.nodeid, action: 'msg', type: 'tunnel', value: '*/meshrelay.ashx?id=' + obj.id, tcpport: cookie.tcpport, tcpaddr: cookie.tcpaddr }; var command = { nodeid: cookie.nodeid, action: 'msg', type: 'tunnel', value: '*/meshrelay.ashx?id=' + obj.id, tcpport: cookie.tcpport, tcpaddr: cookie.tcpaddr };
parent.parent.debug(1, 'Relay: Sending agent tunnel command: ' + JSON.stringify(command)); parent.parent.debug('relay', 'Relay: Sending agent tunnel command: ' + JSON.stringify(command));
if (obj.sendAgentMessage(command, user._id, cookie.domainid) == false) { delete obj.id; parent.parent.debug(1, 'Relay: Unable to contact this agent (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); } if (obj.sendAgentMessage(command, user._id, cookie.domainid) == false) { delete obj.id; parent.parent.debug('relay', 'Relay: Unable to contact this agent (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); }
performRelay(); performRelay();
}); });
return obj; return obj;
@ -390,12 +390,12 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
if (req.query.tcpport != null) { if (req.query.tcpport != null) {
var command = { nodeid: req.query.nodeid, action: 'msg', type: 'tunnel', value: '*/meshrelay.ashx?id=' + obj.id, tcpport: req.query.tcpport, tcpaddr: ((req.query.tcpaddr == null) ? '127.0.0.1' : req.query.tcpaddr) }; var command = { nodeid: req.query.nodeid, action: 'msg', type: 'tunnel', value: '*/meshrelay.ashx?id=' + obj.id, tcpport: req.query.tcpport, tcpaddr: ((req.query.tcpaddr == null) ? '127.0.0.1' : req.query.tcpaddr) };
parent.parent.debug(1, 'Relay: Sending agent TCP tunnel command: ' + JSON.stringify(command)); parent.parent.debug('relay', 'Relay: Sending agent TCP tunnel command: ' + JSON.stringify(command));
if (obj.sendAgentMessage(command, user._id, domain.id) == false) { delete obj.id; parent.parent.debug(1, 'Relay: Unable to contact this agent (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); } if (obj.sendAgentMessage(command, user._id, domain.id) == false) { delete obj.id; parent.parent.debug('relay', 'Relay: Unable to contact this agent (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); }
} else if (req.query.udpport != null) { } else if (req.query.udpport != null) {
var command = { nodeid: req.query.nodeid, action: 'msg', type: 'tunnel', value: '*/meshrelay.ashx?id=' + obj.id, udpport: req.query.udpport, udpaddr: ((req.query.udpaddr == null) ? '127.0.0.1' : req.query.udpaddr) }; var command = { nodeid: req.query.nodeid, action: 'msg', type: 'tunnel', value: '*/meshrelay.ashx?id=' + obj.id, udpport: req.query.udpport, udpaddr: ((req.query.udpaddr == null) ? '127.0.0.1' : req.query.udpaddr) };
parent.parent.debug(1, 'Relay: Sending agent UDP tunnel command: ' + JSON.stringify(command)); parent.parent.debug('relay', 'Relay: Sending agent UDP tunnel command: ' + JSON.stringify(command));
if (obj.sendAgentMessage(command, user._id, domain.id) == false) { delete obj.id; parent.parent.debug(1, 'Relay: Unable to contact this agent (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); } if (obj.sendAgentMessage(command, user._id, domain.id) == false) { delete obj.id; parent.parent.debug('relay', 'Relay: Unable to contact this agent (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); }
} }
performRelay(); performRelay();
}); });

View File

@ -53,8 +53,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Disconnect this user // Disconnect this user
obj.close = function (arg) { obj.close = function (arg) {
if ((arg == 1) || (arg == null)) { try { ws.close(); parent.parent.debug(1, 'Soft disconnect'); } catch (e) { console.log(e); } } // Soft close, close the websocket if ((arg == 1) || (arg == null)) { try { ws.close(); parent.parent.debug('user', 'Soft disconnect'); } catch (e) { console.log(e); } } // Soft close, close the websocket
if (arg == 2) { try { ws._socket._parent.end(); parent.parent.debug(1, 'Hard disconnect'); } catch (e) { console.log(e); } } // Hard close, close the TCP socket if (arg == 2) { try { ws._socket._parent.end(); parent.parent.debug('user', 'Hard disconnect'); } catch (e) { console.log(e); } } // Hard close, close the TCP socket
// Perform cleanup // Perform cleanup
parent.parent.RemoveAllEventDispatch(ws); parent.parent.RemoveAllEventDispatch(ws);
@ -314,6 +314,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Send user information to web socket, this is the first thing we send // Send user information to web socket, this is the first thing we send
try { ws.send(JSON.stringify({ action: 'userinfo', userinfo: parent.CloneSafeUser(parent.users[user._id]) })); } catch (ex) { } try { ws.send(JSON.stringify({ action: 'userinfo', userinfo: parent.CloneSafeUser(parent.users[user._id]) })); } catch (ex) { }
// Send server tracing information
if (user.siteadmin == 0xFFFFFFFF) {
try { ws.send(JSON.stringify({ action: 'traceinfo', traceSources: parent.parent.debugRemoteSources })); } catch (ex) { }
}
// We are all set, start receiving data // We are all set, start receiving data
ws._socket.resume(); ws._socket.resume();
}); });
@ -2729,6 +2734,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
ws.send(JSON.stringify({ action: 'createInviteLink', meshid: command.meshid, expire: command.expire, cookie: inviteCookie })); ws.send(JSON.stringify({ action: 'createInviteLink', meshid: command.meshid, expire: command.expire, cookie: inviteCookie }));
break; break;
} }
case 'traceinfo': {
if ((user.siteadmin == 0xFFFFFFFF) && (typeof command.traceSources == 'object')) {
parent.parent.debugRemoteSources = command.traceSources;
parent.parent.DispatchEvent(['*'], obj, { action: 'traceinfo', userid: user._id, username: user.name, traceSources: command.traceSources, nolog: 1, domain: domain.id });
}
break;
}
default: { default: {
// Unknown user action // Unknown user action
console.log('Unknown action from user ' + user.name + ': ' + command.action + '.'); console.log('Unknown action from user ' + user.name + ': ' + command.action + '.');

View File

@ -167,11 +167,11 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
socket.tag = { first: true, clientCert: socket.getPeerCertificate(true), accumulator: "", activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 }; socket.tag = { first: true, clientCert: socket.getPeerCertificate(true), accumulator: "", activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
} }
socket.setEncoding("binary"); socket.setEncoding("binary");
Debug(1, "MPS:New CIRA connection"); parent.debug('mps', "New CIRA connection");
// Setup the CIRA keep alive timer // Setup the CIRA keep alive timer
socket.setTimeout(MAX_IDLE); socket.setTimeout(MAX_IDLE);
socket.on("timeout", () => { ciraTimeoutCount++; Debug(1, "MPS:CIRA timeout, disconnecting."); try { socket.end(); } catch (e) { } }); socket.on("timeout", () => { ciraTimeoutCount++; parent.debug('mps', "CIRA timeout, disconnecting."); try { socket.end(); } catch (e) { } });
socket.addListener("data", function (data) { socket.addListener("data", function (data) {
if (args.mpsdebug) { var buf = Buffer.from(data, "binary"); console.log("MPS <-- (" + buf.length + "):" + buf.toString('hex')); } // Print out received bytes if (args.mpsdebug) { var buf = Buffer.from(data, "binary"); console.log("MPS <-- (" + buf.length + "):" + buf.toString('hex')); } // Print out received bytes
@ -299,13 +299,13 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
switch (cmd) { switch (cmd) {
case APFProtocol.KEEPALIVE_REQUEST: { case APFProtocol.KEEPALIVE_REQUEST: {
if (len < 5) return 0; if (len < 5) return 0;
Debug(3, 'MPS:KEEPALIVE_REQUEST'); parent.debug('mpscmd', 'KEEPALIVE_REQUEST');
SendKeepAliveReply(socket, common.ReadInt(data, 1)); SendKeepAliveReply(socket, common.ReadInt(data, 1));
return 5; return 5;
} }
case APFProtocol.KEEPALIVE_REPLY: { case APFProtocol.KEEPALIVE_REPLY: {
if (len < 5) return 0; if (len < 5) return 0;
Debug(3, 'MPS:KEEPALIVE_REPLY'); parent.debug('mpscmd', 'KEEPALIVE_REPLY');
return 5; return 5;
} }
case APFProtocol.PROTOCOLVERSION: { case APFProtocol.PROTOCOLVERSION: {
@ -314,7 +314,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
socket.tag.MajorVersion = common.ReadInt(data, 1); socket.tag.MajorVersion = common.ReadInt(data, 1);
socket.tag.MinorVersion = common.ReadInt(data, 5); socket.tag.MinorVersion = common.ReadInt(data, 5);
socket.tag.SystemId = guidToStr(common.rstr2hex(data.substring(13, 29))).toLowerCase(); socket.tag.SystemId = guidToStr(common.rstr2hex(data.substring(13, 29))).toLowerCase();
Debug(3, 'MPS:PROTOCOLVERSION', socket.tag.MajorVersion, socket.tag.MinorVersion, socket.tag.SystemId); parent.debug('mpscmd', 'PROTOCOLVERSION', socket.tag.MajorVersion, socket.tag.MinorVersion, socket.tag.SystemId);
return 93; return 93;
} }
case APFProtocol.USERAUTH_REQUEST: { case APFProtocol.USERAUTH_REQUEST: {
@ -332,16 +332,16 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
password = data.substring(18 + usernameLen + serviceNameLen + methodNameLen, 18 + usernameLen + serviceNameLen + methodNameLen + passwordLen); password = data.substring(18 + usernameLen + serviceNameLen + methodNameLen, 18 + usernameLen + serviceNameLen + methodNameLen + passwordLen);
} }
//console.log('MPS:USERAUTH_REQUEST user=' + username + ', service=' + serviceName + ', method=' + methodName + ', password=' + password); //console.log('MPS:USERAUTH_REQUEST user=' + username + ', service=' + serviceName + ', method=' + methodName + ', password=' + password);
Debug(3, 'MPS:USERAUTH_REQUEST user=' + username + ', service=' + serviceName + ', method=' + methodName + ', password=' + password); parent.debug('mpscmd', 'USERAUTH_REQUEST user=' + username + ', service=' + serviceName + ', method=' + methodName + ', password=' + password);
// Check the CIRA password // Check the CIRA password
if ((args.mpspass != null) && (password != args.mpspass)) { incorrectPasswordCount++; Debug(1, 'MPS:Incorrect password', username, password); SendUserAuthFail(socket); return -1; } if ((args.mpspass != null) && (password != args.mpspass)) { incorrectPasswordCount++; parent.debug('mps', 'Incorrect password', username, password); SendUserAuthFail(socket); return -1; }
// Check the CIRA username, which should be the start of the MeshID. // Check the CIRA username, which should be the start of the MeshID.
if (usernameLen != 16) { badUserNameLengthCount++; Debug(1, 'MPS:Username length not 16', username, password); SendUserAuthFail(socket); return -1; } if (usernameLen != 16) { badUserNameLengthCount++; parent.debug('mps', 'Username length not 16', username, password); SendUserAuthFail(socket); return -1; }
var meshIdStart = '/' + username, mesh = null; var meshIdStart = '/' + username, mesh = null;
if (obj.parent.webserver.meshes) { for (var i in obj.parent.webserver.meshes) { if (obj.parent.webserver.meshes[i]._id.replace(/\@/g, 'X').replace(/\$/g, 'X').indexOf(meshIdStart) > 0) { mesh = obj.parent.webserver.meshes[i]; break; } } } if (obj.parent.webserver.meshes) { for (var i in obj.parent.webserver.meshes) { if (obj.parent.webserver.meshes[i]._id.replace(/\@/g, 'X').replace(/\$/g, 'X').indexOf(meshIdStart) > 0) { mesh = obj.parent.webserver.meshes[i]; break; } } }
if (mesh == null) { meshNotFoundCount++; Debug(1, 'MPS:Mesh not found', username, password); SendUserAuthFail(socket); return -1; } if (mesh == null) { meshNotFoundCount++; parent.debug('mps', 'Mesh not found', username, password); SendUserAuthFail(socket); return -1; }
// If this is a agent-less mesh, use the device guid 3 times as ID. // If this is a agent-less mesh, use the device guid 3 times as ID.
if (mesh.mtype == 1) { if (mesh.mtype == 1) {
@ -446,7 +446,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
var xserviceNameLen = common.ReadInt(data, 1); var xserviceNameLen = common.ReadInt(data, 1);
if (len < 5 + xserviceNameLen) return 0; if (len < 5 + xserviceNameLen) return 0;
var xserviceName = data.substring(5, 5 + xserviceNameLen); var xserviceName = data.substring(5, 5 + xserviceNameLen);
Debug(3, 'MPS:SERVICE_REQUEST', xserviceName); parent.debug('mpscmd', 'SERVICE_REQUEST', xserviceName);
if (xserviceName == "pfwd@amt.intel.com") { SendServiceAccept(socket, "pfwd@amt.intel.com"); } if (xserviceName == "pfwd@amt.intel.com") { SendServiceAccept(socket, "pfwd@amt.intel.com"); }
if (xserviceName == "auth@amt.intel.com") { SendServiceAccept(socket, "auth@amt.intel.com"); } if (xserviceName == "auth@amt.intel.com") { SendServiceAccept(socket, "auth@amt.intel.com"); }
return 5 + xserviceNameLen; return 5 + xserviceNameLen;
@ -463,7 +463,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
if (len < 14 + requestLen + addrLen) return 0; if (len < 14 + requestLen + addrLen) return 0;
var addr = data.substring(10 + requestLen, 10 + requestLen + addrLen); var addr = data.substring(10 + requestLen, 10 + requestLen + addrLen);
var port = common.ReadInt(data, 10 + requestLen + addrLen); var port = common.ReadInt(data, 10 + requestLen + addrLen);
Debug(2, 'MPS:GLOBAL_REQUEST', request, addr + ':' + port); parent.debug('mpscmd', 'GLOBAL_REQUEST', request, addr + ':' + port);
ChangeHostname(socket, addr, socket.tag.SystemId); ChangeHostname(socket, addr, socket.tag.SystemId);
if (socket.tag.boundPorts.indexOf(port) == -1) { socket.tag.boundPorts.push(port); } if (socket.tag.boundPorts.indexOf(port) == -1) { socket.tag.boundPorts.push(port); }
SendTcpForwardSuccessReply(socket, port); SendTcpForwardSuccessReply(socket, port);
@ -475,7 +475,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
if (len < 14 + requestLen + addrLen) return 0; if (len < 14 + requestLen + addrLen) return 0;
var addr = data.substring(10 + requestLen, 10 + requestLen + addrLen); var addr = data.substring(10 + requestLen, 10 + requestLen + addrLen);
var port = common.ReadInt(data, 10 + requestLen + addrLen); var port = common.ReadInt(data, 10 + requestLen + addrLen);
Debug(2, 'MPS:GLOBAL_REQUEST', request, addr + ':' + port); parent.debug('mpscmd', 'GLOBAL_REQUEST', request, addr + ':' + port);
var portindex = socket.tag.boundPorts.indexOf(port); var portindex = socket.tag.boundPorts.indexOf(port);
if (portindex >= 0) { socket.tag.boundPorts.splice(portindex, 1); } if (portindex >= 0) { socket.tag.boundPorts.splice(portindex, 1); }
SendTcpForwardCancelReply(socket); SendTcpForwardCancelReply(socket);
@ -493,7 +493,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
var oport = common.ReadInt(data, 18 + requestLen + addrLen + oaddrLen); var oport = common.ReadInt(data, 18 + requestLen + addrLen + oaddrLen);
var datalen = common.ReadInt(data, 22 + requestLen + addrLen + oaddrLen); var datalen = common.ReadInt(data, 22 + requestLen + addrLen + oaddrLen);
if (len < 26 + requestLen + addrLen + oaddrLen + datalen) return 0; if (len < 26 + requestLen + addrLen + oaddrLen + datalen) return 0;
Debug(2, 'MPS:GLOBAL_REQUEST', request, addr + ':' + port, oaddr + ':' + oport, datalen); parent.debug('mpscmd', 'GLOBAL_REQUEST', request, addr + ':' + port, oaddr + ':' + oport, datalen);
// TODO // TODO
return 26 + requestLen + addrLen + oaddrLen + datalen; return 26 + requestLen + addrLen + oaddrLen + datalen;
} }
@ -523,7 +523,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
var SourcePort = common.ReadInt(data, 29 + ChannelTypeLength + TargetLen + SourceLen); var SourcePort = common.ReadInt(data, 29 + ChannelTypeLength + TargetLen + SourceLen);
channelOpenCount++; channelOpenCount++;
Debug(3, 'MPS:CHANNEL_OPEN', ChannelType, SenderChannel, WindowSize, Target + ':' + TargetPort, Source + ':' + SourcePort); parent.debug('mpscmd', 'CHANNEL_OPEN', ChannelType, SenderChannel, WindowSize, Target + ':' + TargetPort, Source + ':' + SourcePort);
// Check if we understand this channel type // Check if we understand this channel type
//if (ChannelType.toLowerCase() == "direct-tcpip") //if (ChannelType.toLowerCase() == "direct-tcpip")
@ -554,7 +554,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
cirachannel.amtchannelid = SenderChannel; cirachannel.amtchannelid = SenderChannel;
cirachannel.sendcredits = cirachannel.amtCiraWindow = WindowSize; cirachannel.sendcredits = cirachannel.amtCiraWindow = WindowSize;
channelOpenConfirmCount++; channelOpenConfirmCount++;
Debug(3, 'MPS:CHANNEL_OPEN_CONFIRMATION', RecipientChannel, SenderChannel, WindowSize); parent.debug('mpscmd', 'CHANNEL_OPEN_CONFIRMATION', RecipientChannel, SenderChannel, WindowSize);
if (cirachannel.closing == 1) { if (cirachannel.closing == 1) {
// Close this channel // Close this channel
SendChannelClose(cirachannel.socket, cirachannel.amtchannelid); SendChannelClose(cirachannel.socket, cirachannel.amtchannelid);
@ -586,7 +586,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
var RecipientChannel = common.ReadInt(data, 1); var RecipientChannel = common.ReadInt(data, 1);
var ReasonCode = common.ReadInt(data, 5); var ReasonCode = common.ReadInt(data, 5);
channelOpenFailCount++; channelOpenFailCount++;
Debug(3, 'MPS:CHANNEL_OPEN_FAILURE', RecipientChannel, ReasonCode); parent.debug('mpscmd', 'CHANNEL_OPEN_FAILURE', RecipientChannel, ReasonCode);
var cirachannel = socket.tag.channels[RecipientChannel]; var cirachannel = socket.tag.channels[RecipientChannel];
if (cirachannel == null) { console.log("MPS Error in CHANNEL_OPEN_FAILURE: Unable to find channelid " + RecipientChannel); return 17; } if (cirachannel == null) { console.log("MPS Error in CHANNEL_OPEN_FAILURE: Unable to find channelid " + RecipientChannel); return 17; }
if (cirachannel.state > 0) { if (cirachannel.state > 0) {
@ -601,7 +601,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
if (len < 5) return 0; if (len < 5) return 0;
var RecipientChannel = common.ReadInt(data, 1); var RecipientChannel = common.ReadInt(data, 1);
channelCloseCount++; channelCloseCount++;
Debug(3, 'MPS:CHANNEL_CLOSE', RecipientChannel); parent.debug('mpscmd', 'CHANNEL_CLOSE', RecipientChannel);
var cirachannel = socket.tag.channels[RecipientChannel]; var cirachannel = socket.tag.channels[RecipientChannel];
if (cirachannel == null) { console.log("MPS Error in CHANNEL_CLOSE: Unable to find channelid " + RecipientChannel); return 5; } if (cirachannel == null) { console.log("MPS Error in CHANNEL_CLOSE: Unable to find channelid " + RecipientChannel); return 5; }
socket.tag.activetunnels--; socket.tag.activetunnels--;
@ -620,7 +620,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
var cirachannel = socket.tag.channels[RecipientChannel]; var cirachannel = socket.tag.channels[RecipientChannel];
if (cirachannel == null) { console.log("MPS Error in CHANNEL_WINDOW_ADJUST: Unable to find channelid " + RecipientChannel); return 9; } if (cirachannel == null) { console.log("MPS Error in CHANNEL_WINDOW_ADJUST: Unable to find channelid " + RecipientChannel); return 9; }
cirachannel.sendcredits += ByteToAdd; cirachannel.sendcredits += ByteToAdd;
Debug(3, 'MPS:CHANNEL_WINDOW_ADJUST', RecipientChannel, ByteToAdd, cirachannel.sendcredits); parent.debug('mpscmd', 'CHANNEL_WINDOW_ADJUST', RecipientChannel, ByteToAdd, cirachannel.sendcredits);
if (cirachannel.state == 2 && cirachannel.sendBuffer != null) { if (cirachannel.state == 2 && cirachannel.sendBuffer != null) {
// Compute how much data we can send // Compute how much data we can send
if (cirachannel.sendBuffer.length <= cirachannel.sendcredits) { if (cirachannel.sendBuffer.length <= cirachannel.sendcredits) {
@ -644,7 +644,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
var RecipientChannel = common.ReadInt(data, 1); var RecipientChannel = common.ReadInt(data, 1);
var LengthOfData = common.ReadInt(data, 5); var LengthOfData = common.ReadInt(data, 5);
if (len < (9 + LengthOfData)) return 0; if (len < (9 + LengthOfData)) return 0;
Debug(4, 'MPS:CHANNEL_DATA', RecipientChannel, LengthOfData); parent.debug('mpscmddata', 'CHANNEL_DATA', RecipientChannel, LengthOfData);
var cirachannel = socket.tag.channels[RecipientChannel]; var cirachannel = socket.tag.channels[RecipientChannel];
if (cirachannel == null) { console.log("MPS Error in CHANNEL_DATA: Unable to find channelid " + RecipientChannel); return 9 + LengthOfData; } if (cirachannel == null) { console.log("MPS Error in CHANNEL_DATA: Unable to find channelid " + RecipientChannel); return 9 + LengthOfData; }
cirachannel.amtpendingcredits += LengthOfData; cirachannel.amtpendingcredits += LengthOfData;
@ -660,14 +660,14 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
if (len < 7) return 0; if (len < 7) return 0;
var ReasonCode = common.ReadInt(data, 1); var ReasonCode = common.ReadInt(data, 1);
disconnectCommandCount++; disconnectCommandCount++;
Debug(3, 'MPS:DISCONNECT', ReasonCode); parent.debug('mpscmd', 'DISCONNECT', ReasonCode);
try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { } try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2); obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
return 7; return 7;
} }
default: default:
{ {
Debug(1, 'MPS:Unknown CIRA command: ' + cmd); parent.debug('mpscmd', 'Unknown CIRA command: ' + cmd);
return -1; return -1;
} }
} }
@ -675,7 +675,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
socket.addListener("close", function () { socket.addListener("close", function () {
socketClosedCount++; socketClosedCount++;
Debug(1, 'MPS:CIRA connection closed'); parent.debug('mps', 'CIRA connection closed');
try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { } try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2); obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
}); });
@ -741,7 +741,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
} }
function SendChannelWindowAdjust(socket, channelid, bytestoadd) { function SendChannelWindowAdjust(socket, channelid, bytestoadd) {
Debug(3, 'MPS:SendChannelWindowAdjust', channelid, bytestoadd); parent.debug('mpscmd', 'SendChannelWindowAdjust', channelid, bytestoadd);
Write(socket, String.fromCharCode(APFProtocol.CHANNEL_WINDOW_ADJUST) + common.IntToStr(channelid) + common.IntToStr(bytestoadd)); Write(socket, String.fromCharCode(APFProtocol.CHANNEL_WINDOW_ADJUST) + common.IntToStr(channelid) + common.IntToStr(bytestoadd));
} }
@ -853,16 +853,5 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
function guidToStr(g) { return g.substring(6, 8) + g.substring(4, 6) + g.substring(2, 4) + g.substring(0, 2) + "-" + g.substring(10, 12) + g.substring(8, 10) + "-" + g.substring(14, 16) + g.substring(12, 14) + "-" + g.substring(16, 20) + "-" + g.substring(20); } function guidToStr(g) { return g.substring(6, 8) + g.substring(4, 6) + g.substring(2, 4) + g.substring(0, 2) + "-" + g.substring(10, 12) + g.substring(8, 10) + "-" + g.substring(14, 16) + g.substring(12, 14) + "-" + g.substring(16, 20) + "-" + g.substring(20); }
// Debug
function Debug(lvl) {
if (lvl > obj.parent.debugLevel) return;
if (arguments.length == 2) { console.log(arguments[1]); }
else if (arguments.length == 3) { console.log(arguments[1], arguments[2]); }
else if (arguments.length == 4) { console.log(arguments[1], arguments[2], arguments[3]); }
else if (arguments.length == 5) { console.log(arguments[1], arguments[2], arguments[3], arguments[4]); }
else if (arguments.length == 6) { console.log(arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); }
else if (arguments.length == 7) { console.log(arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6]); }
}
return obj; return obj;
}; };

View File

@ -61,15 +61,15 @@ module.exports.CreateMultiServer = function (parent, args) {
// Get the web socket setup // Get the web socket setup
obj.ws = new WebSocket(obj.url + 'meshserver.ashx', { rejectUnauthorized: false, cert: obj.certificates.agent.cert, key: obj.certificates.agent.key }); obj.ws = new WebSocket(obj.url + 'meshserver.ashx', { rejectUnauthorized: false, cert: obj.certificates.agent.cert, key: obj.certificates.agent.key });
obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Connecting to: ' + url + 'meshserver.ashx'); obj.parent.parent.debug('peer', 'OutPeer ' + obj.serverid + ': Connecting to: ' + url + 'meshserver.ashx');
// Register the connection failed event // Register the connection failed event
obj.ws.on('error', function (error) { obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Error: ' + error); disconnect(); }); obj.ws.on('error', function (error) { obj.parent.parent.debug('peer', 'OutPeer ' + obj.serverid + ': Error: ' + error); disconnect(); });
obj.ws.on('close', function () { obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Disconnected'); disconnect(); }); obj.ws.on('close', function () { obj.parent.parent.debug('peer', 'OutPeer ' + obj.serverid + ': Disconnected'); disconnect(); });
// Register the connection event // Register the connection event
obj.ws.on('open', function () { obj.ws.on('open', function () {
obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Connected'); obj.parent.parent.debug('peer', 'OutPeer ' + obj.serverid + ': Connected');
obj.connectionState |= 2; obj.connectionState |= 2;
obj.nonce = obj.crypto.randomBytes(48).toString('binary'); obj.nonce = obj.crypto.randomBytes(48).toString('binary');
@ -95,10 +95,10 @@ module.exports.CreateMultiServer = function (parent, args) {
switch (cmd) { switch (cmd) {
case 1: { case 1: {
// Server authentication request // Server authentication request
if (msg.length != 98) { obj.parent.parent.debug(1, 'OutPeer: BAD MESSAGE(A1)'); return; } if (msg.length != 98) { obj.parent.parent.debug('peer', 'OutPeer: BAD MESSAGE(A1)'); return; }
// Check that the server hash matches the TLS server certificate public key hash // Check that the server hash matches the TLS server certificate public key hash
if (obj.serverCertHash != msg.substring(2, 50)) { obj.parent.parent.debug(1, 'OutPeer: Server hash mismatch.'); disconnect(); return; } if (obj.serverCertHash != msg.substring(2, 50)) { obj.parent.parent.debug('peer', 'OutPeer: Server hash mismatch.'); disconnect(); return; }
obj.servernonce = msg.substring(50); obj.servernonce = msg.substring(50);
// Perform the hash signature using the server agent certificate // Perform the hash signature using the server agent certificate
@ -114,14 +114,14 @@ module.exports.CreateMultiServer = function (parent, args) {
var certlen = obj.common.ReadShort(msg, 2), serverCert = null; var certlen = obj.common.ReadShort(msg, 2), serverCert = null;
var serverCertPem = '-----BEGIN CERTIFICATE-----\r\n' + Buffer.from(msg.substring(4, 4 + certlen), 'binary').toString('base64') + '\r\n-----END CERTIFICATE-----'; var serverCertPem = '-----BEGIN CERTIFICATE-----\r\n' + Buffer.from(msg.substring(4, 4 + certlen), 'binary').toString('base64') + '\r\n-----END CERTIFICATE-----';
try { serverCert = obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(msg.substring(4, 4 + certlen))); } catch (e) { } try { serverCert = obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(msg.substring(4, 4 + certlen))); } catch (e) { }
if (serverCert == null) { obj.parent.parent.debug(1, 'OutPeer: Invalid server certificate.'); disconnect(); return; } if (serverCert == null) { obj.parent.parent.debug('peer', 'OutPeer: Invalid server certificate.'); disconnect(); return; }
var serverid = Buffer.from(obj.forge.pki.getPublicKeyFingerprint(serverCert.publicKey, { encoding: 'binary', md: obj.forge.md.sha384.create() }), 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); var serverid = Buffer.from(obj.forge.pki.getPublicKeyFingerprint(serverCert.publicKey, { encoding: 'binary', md: obj.forge.md.sha384.create() }), 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
if (serverid !== obj.agentCertificateHashBase64) { obj.parent.parent.debug(1, 'OutPeer: Server hash mismatch.'); disconnect(); return; } if (serverid !== obj.agentCertificateHashBase64) { obj.parent.parent.debug('peer', 'OutPeer: Server hash mismatch.'); disconnect(); return; }
// Server signature, verify it. This is the fast way, without using forge. (TODO: Use accelerator for this?) // Server signature, verify it. This is the fast way, without using forge. (TODO: Use accelerator for this?)
const verify = obj.parent.crypto.createVerify('SHA384'); const verify = obj.parent.crypto.createVerify('SHA384');
verify.end(Buffer.from(obj.serverCertHash + obj.nonce + obj.servernonce, 'binary')); verify.end(Buffer.from(obj.serverCertHash + obj.nonce + obj.servernonce, 'binary'));
if (verify.verify(serverCertPem, Buffer.from(msg.substring(4 + certlen), 'binary')) !== true) { obj.parent.parent.debug(1, 'OutPeer: Server sign check failed.'); disconnect(); return; } if (verify.verify(serverCertPem, Buffer.from(msg.substring(4 + certlen), 'binary')) !== true) { obj.parent.parent.debug('peer', 'OutPeer: Server sign check failed.'); disconnect(); return; }
// Connection is a success, clean up // Connection is a success, clean up
delete obj.nonce; delete obj.nonce;
@ -129,7 +129,7 @@ module.exports.CreateMultiServer = function (parent, args) {
obj.serverCertHash = Buffer.from(obj.serverCertHash, 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); // Change this value to base64 obj.serverCertHash = Buffer.from(obj.serverCertHash, 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); // Change this value to base64
obj.connectionState |= 4; obj.connectionState |= 4;
obj.retryBackoff = 0; // Set backoff connection timer back to fast. obj.retryBackoff = 0; // Set backoff connection timer back to fast.
obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Verified peer connection to ' + obj.url); obj.parent.parent.debug('peer', 'OutPeer ' + obj.serverid + ': Verified peer connection to ' + obj.url);
// Send information about our server to the peer // Send information about our server to the peer
if (obj.connectionState == 15) { if (obj.connectionState == 15) {
@ -152,7 +152,7 @@ module.exports.CreateMultiServer = function (parent, args) {
break; break;
} }
default: { default: {
obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Un-handled command: ' + cmd); obj.parent.parent.debug('peer', 'OutPeer ' + obj.serverid + ': Un-handled command: ' + cmd);
break; break;
} }
} }
@ -189,7 +189,7 @@ module.exports.CreateMultiServer = function (parent, args) {
function processServerData(msg) { function processServerData(msg) {
var str = msg.toString('utf8'), command = null; var str = msg.toString('utf8'), command = null;
if (str[0] == '{') { if (str[0] == '{') {
try { command = JSON.parse(str); } catch (e) { obj.parent.parent.debug(1, 'Unable to parse server JSON (' + obj.remoteaddr + ').'); return; } // If the command can't be parsed, ignore it. try { command = JSON.parse(str); } catch (e) { obj.parent.parent.debug('peer', 'Unable to parse server JSON (' + obj.remoteaddr + ').'); return; } // If the command can't be parsed, ignore it.
if (command.action == 'info') { if (command.action == 'info') {
if (obj.authenticated != 3) { if (obj.authenticated != 3) {
// We get the peer's serverid and database identifier. // We get the peer's serverid and database identifier.
@ -233,7 +233,7 @@ module.exports.CreateMultiServer = function (parent, args) {
obj.serverCertHash = null; obj.serverCertHash = null;
obj.pendingData = []; obj.pendingData = [];
if (obj.remoteaddr.startsWith('::ffff:')) { obj.remoteaddr = obj.remoteaddr.substring(7); } if (obj.remoteaddr.startsWith('::ffff:')) { obj.remoteaddr = obj.remoteaddr.substring(7); }
obj.parent.parent.debug(1, 'InPeer: Connected (' + obj.remoteaddr + ')'); obj.parent.parent.debug('peer', 'InPeer: Connected (' + obj.remoteaddr + ')');
// Send a message to the peer server // Send a message to the peer server
obj.send = function (data) { obj.send = function (data) {
@ -246,8 +246,8 @@ module.exports.CreateMultiServer = function (parent, args) {
// Disconnect this server // Disconnect this server
obj.close = function (arg) { obj.close = function (arg) {
if ((arg == 1) || (arg == null)) { try { obj.ws.close(); obj.parent.parent.debug(1, 'InPeer: Soft disconnect ' + obj.peerServerId + ' (' + obj.remoteaddr + ')'); } catch (e) { console.log(e); } } // Soft close, close the websocket if ((arg == 1) || (arg == null)) { try { obj.ws.close(); obj.parent.parent.debug('peer', 'InPeer: Soft disconnect ' + obj.peerServerId + ' (' + obj.remoteaddr + ')'); } catch (e) { console.log(e); } } // Soft close, close the websocket
if (arg == 2) { try { obj.ws._socket._parent.end(); obj.parent.parent.debug(1, 'InPeer: Hard disconnect ' + obj.peerServerId + ' (' + obj.remoteaddr + ')'); } catch (e) { console.log(e); } } // Hard close, close the TCP socket if (arg == 2) { try { obj.ws._socket._parent.end(); obj.parent.parent.debug('peer', 'InPeer: Hard disconnect ' + obj.peerServerId + ' (' + obj.remoteaddr + ')'); } catch (e) { console.log(e); } } // Hard close, close the TCP socket
if (obj.authenticated == 3) { obj.parent.ClearPeerServer(obj, obj.peerServerId); obj.authenticated = 0; } if (obj.authenticated == 3) { obj.parent.ClearPeerServer(obj, obj.peerServerId); obj.authenticated = 0; }
}; };
@ -283,7 +283,7 @@ module.exports.CreateMultiServer = function (parent, args) {
} }
else if (cmd == 2) { else if (cmd == 2) {
// Peer server certificate // Peer server certificate
if ((msg.length < 4) || ((obj.receivedCommands & 2) != 0)) { obj.parent.parent.debug(1, 'InPeer: Invalid command 2.'); return; } if ((msg.length < 4) || ((obj.receivedCommands & 2) != 0)) { obj.parent.parent.debug('peer', 'InPeer: Invalid command 2.'); return; }
obj.receivedCommands += 2; // Peer server can't send the same command twice on the same connection ever. Block DOS attack path. obj.receivedCommands += 2; // Peer server can't send the same command twice on the same connection ever. Block DOS attack path.
// Decode the certificate // Decode the certificate
@ -296,12 +296,12 @@ module.exports.CreateMultiServer = function (parent, args) {
if (obj.peernonce == null) { if (obj.peernonce == null) {
obj.unauthsign = msg.substring(4 + certlen); obj.unauthsign = msg.substring(4 + certlen);
} else { } else {
if (processPeerSignature(msg.substring(4 + certlen)) == false) { obj.parent.parent.debug(1, 'InPeer: Invalid signature.'); obj.close(); return; } if (processPeerSignature(msg.substring(4 + certlen)) == false) { obj.parent.parent.debug('peer', 'InPeer: Invalid signature.'); obj.close(); return; }
} }
completePeerServerConnection(); completePeerServerConnection();
} }
else if (cmd == 3) { else if (cmd == 3) {
if ((msg.length < 56) || ((obj.receivedCommands & 4) != 0)) { obj.parent.parent.debug(1, 'InPeer: Invalid command 3.'); return; } if ((msg.length < 56) || ((obj.receivedCommands & 4) != 0)) { obj.parent.parent.debug('peer', 'InPeer: Invalid command 3.'); return; }
obj.receivedCommands += 4; // Peer server can't send the same command twice on the same connection ever. Block DOS attack path. obj.receivedCommands += 4; // Peer server can't send the same command twice on the same connection ever. Block DOS attack path.
completePeerServerConnection(); completePeerServerConnection();
} }
@ -309,11 +309,11 @@ module.exports.CreateMultiServer = function (parent, args) {
}); });
// If error, do nothing // If error, do nothing
ws.on('error', function (err) { obj.parent.parent.debug(1, 'InPeer: Connection Error: ' + err); }); ws.on('error', function (err) { obj.parent.parent.debug('peer', 'InPeer: Connection Error: ' + err); });
// If the peer server web socket is closed, clean up. // If the peer server web socket is closed, clean up.
ws.on('close', function (req) { obj.parent.parent.debug(1, 'InPeer disconnect ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); obj.close(0); }); ws.on('close', function (req) { obj.parent.parent.debug('peer', 'InPeer disconnect ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); obj.close(0); });
// obj.ws._socket._parent.on('close', function (req) { obj.parent.parent.debug(1, 'Peer server TCP disconnect ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); }); // obj.ws._socket._parent.on('close', function (req) { obj.parent.parent.debug('peer', 'Peer server TCP disconnect ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); });
// Start authenticate the peer server by sending a auth nonce & server TLS cert hash. // Start authenticate the peer server by sending a auth nonce & server TLS cert hash.
// Send 384 bits SHA382 hash of TLS cert public key + 384 bits nonce // Send 384 bits SHA382 hash of TLS cert public key + 384 bits nonce
@ -355,7 +355,7 @@ module.exports.CreateMultiServer = function (parent, args) {
function processServerData(msg) { function processServerData(msg) {
var str = msg.toString('utf8'), command = null; var str = msg.toString('utf8'), command = null;
if (str[0] == '{') { if (str[0] == '{') {
try { command = JSON.parse(str); } catch (e) { obj.parent.parent.debug(1, 'Unable to parse server JSON (' + obj.remoteaddr + ').'); return; } // If the command can't be parsed, ignore it. try { command = JSON.parse(str); } catch (e) { obj.parent.parent.debug('peer', 'Unable to parse server JSON (' + obj.remoteaddr + ').'); return; } // If the command can't be parsed, ignore it.
if (command.action == 'info') { if (command.action == 'info') {
if (obj.authenticated != 3) { if (obj.authenticated != 3) {
// We get the peer's serverid and database identifier. // We get the peer's serverid and database identifier.
@ -599,21 +599,21 @@ module.exports.CreateMultiServer = function (parent, args) {
peerTunnel.connect = function () { peerTunnel.connect = function () {
// Get the web socket setup // Get the web socket setup
peerTunnel.parent.parent.debug(1, 'FTunnel ' + peerTunnel.serverid + ': Start connect to ' + peerTunnel.url); peerTunnel.parent.parent.debug('peer', 'FTunnel ' + peerTunnel.serverid + ': Start connect to ' + peerTunnel.url);
peerTunnel.ws2 = new WebSocket(peerTunnel.url, { rejectUnauthorized: false }); peerTunnel.ws2 = new WebSocket(peerTunnel.url, { rejectUnauthorized: false });
// Register the connection failed event // Register the connection failed event
peerTunnel.ws2.on('error', function (error) { peerTunnel.parent.parent.debug(1, 'FTunnel ' + obj.serverid + ': Connection error'); peerTunnel.close(); }); peerTunnel.ws2.on('error', function (error) { peerTunnel.parent.parent.debug('peer', 'FTunnel ' + obj.serverid + ': Connection error'); peerTunnel.close(); });
// If the peer server web socket is closed, clean up. // If the peer server web socket is closed, clean up.
peerTunnel.ws2.on('close', function (req) { peerTunnel.parent.parent.debug(1, 'FTunnel disconnect ' + peerTunnel.serverid); peerTunnel.close(); }); peerTunnel.ws2.on('close', function (req) { peerTunnel.parent.parent.debug('peer', 'FTunnel disconnect ' + peerTunnel.serverid); peerTunnel.close(); });
// If a message is received from the peer, Peer ---> Browser (TODO: Pipe this?) // If a message is received from the peer, Peer ---> Browser (TODO: Pipe this?)
peerTunnel.ws2.on('message', function (msg) { try { peerTunnel.ws2._socket.pause(); peerTunnel.ws1.send(msg, function () { peerTunnel.ws2._socket.resume(); }); } catch (e) { } }); peerTunnel.ws2.on('message', function (msg) { try { peerTunnel.ws2._socket.pause(); peerTunnel.ws1.send(msg, function () { peerTunnel.ws2._socket.resume(); }); } catch (e) { } });
// Register the connection event // Register the connection event
peerTunnel.ws2.on('open', function () { peerTunnel.ws2.on('open', function () {
peerTunnel.parent.parent.debug(1, 'FTunnel ' + peerTunnel.serverid + ': Connected'); peerTunnel.parent.parent.debug('peer', 'FTunnel ' + peerTunnel.serverid + ': Connected');
// Get the peer server's certificate and compute the server public key hash // Get the peer server's certificate and compute the server public key hash
var serverCert = obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(peerTunnel.ws2._socket.getPeerCertificate().raw.toString('binary'))); var serverCert = obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(peerTunnel.ws2._socket.getPeerCertificate().raw.toString('binary')));
@ -633,19 +633,19 @@ module.exports.CreateMultiServer = function (parent, args) {
peerTunnel.ws1.on('error', function (err) { peerTunnel.close(); }); peerTunnel.ws1.on('error', function (err) { peerTunnel.close(); });
// If the web socket is closed, close the associated TCP connection. // If the web socket is closed, close the associated TCP connection.
peerTunnel.ws1.on('close', function (req) { peerTunnel.parent.parent.debug(1, 'FTunnel disconnect ' + peerTunnel.serverid); peerTunnel.close(); }); peerTunnel.ws1.on('close', function (req) { peerTunnel.parent.parent.debug('peer', 'FTunnel disconnect ' + peerTunnel.serverid); peerTunnel.close(); });
}; };
// Disconnect both sides of the tunnel // Disconnect both sides of the tunnel
peerTunnel.close = function (arg) { peerTunnel.close = function (arg) {
if (arg == 2) { if (arg == 2) {
// Hard close, close the TCP socket // Hard close, close the TCP socket
if (peerTunnel.ws1 != null) { try { peerTunnel.ws1._socket._parent.end(); peerTunnel.parent.parent.debug(1, 'FTunnel1: Hard disconnect'); } catch (e) { console.log(e); } } if (peerTunnel.ws1 != null) { try { peerTunnel.ws1._socket._parent.end(); peerTunnel.parent.parent.debug('peer', 'FTunnel1: Hard disconnect'); } catch (e) { console.log(e); } }
if (peerTunnel.ws2 != null) { try { peerTunnel.ws2._socket._parent.end(); peerTunnel.parent.parent.debug(1, 'FTunnel2: Hard disconnect'); } catch (e) { console.log(e); } } if (peerTunnel.ws2 != null) { try { peerTunnel.ws2._socket._parent.end(); peerTunnel.parent.parent.debug('peer', 'FTunnel2: Hard disconnect'); } catch (e) { console.log(e); } }
} else { } else {
// Soft close, close the websocket // Soft close, close the websocket
if (peerTunnel.ws1 != null) { try { peerTunnel.ws1.close(); peerTunnel.parent.parent.debug(1, 'FTunnel1: Soft disconnect '); } catch (e) { console.log(e); } } if (peerTunnel.ws1 != null) { try { peerTunnel.ws1.close(); peerTunnel.parent.parent.debug('peer', 'FTunnel1: Soft disconnect '); } catch (e) { console.log(e); } }
if (peerTunnel.ws2 != null) { try { peerTunnel.ws2.close(); peerTunnel.parent.parent.debug(1, 'FTunnel2: Soft disconnect '); } catch (e) { console.log(e); } } if (peerTunnel.ws2 != null) { try { peerTunnel.ws2.close(); peerTunnel.parent.parent.debug('peer', 'FTunnel2: Soft disconnect '); } catch (e) { console.log(e); } }
} }
}; };

View File

@ -1,6 +1,6 @@
{ {
"name": "meshcentral", "name": "meshcentral",
"version": "0.4.0-a", "version": "0.4.0-c",
"keywords": [ "keywords": [
"Remote Management", "Remote Management",
"Intel AMT", "Intel AMT",

View File

@ -838,7 +838,7 @@ NoMeshesPanel img {
color: gray; color: gray;
} }
#p3events, #p16events, #p31events { #p3events, #p16events, #p31events, #p41events {
height: calc(100vh - 245px); height: calc(100vh - 245px);
overflow-y: scroll; overflow-y: scroll;
} }
@ -2540,3 +2540,13 @@ a {
padding:6px; padding:6px;
box-shadow: 0px 0px 15px #666; box-shadow: 0px 0px 15px #666;
} }
.traceEvent {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin: 3px 3px 3px 0;
padding: 3px;
border-radius: 3px;
background-color: #DDD;
}

View File

@ -10,6 +10,7 @@
"_Minify": 1, "_Minify": 1,
"_SessionTime": 30, "_SessionTime": 30,
"_SessionKey": "MyReallySecretPassword1", "_SessionKey": "MyReallySecretPassword1",
"_SessionSameSite": "strict",
"_DbEncryptKey": "MyReallySecretPassword2", "_DbEncryptKey": "MyReallySecretPassword2",
"_DbExpire": { "_DbExpire": {
"events": 1728000, "events": 1728000,
@ -20,6 +21,7 @@
"_AllowLoginToken": true, "_AllowLoginToken": true,
"_AllowFraming": true, "_AllowFraming": true,
"_WebRTC": false, "_WebRTC": false,
"_Nice404": false,
"_ClickOnce": false, "_ClickOnce": false,
"_SelfUpdate": true, "_SelfUpdate": true,
"_AgentPing": 60, "_AgentPing": 60,

View File

@ -202,11 +202,11 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
switch (cmd) { switch (cmd) {
case LegacyMeshProtocol.NODEPUSH: { case LegacyMeshProtocol.NODEPUSH: {
Debug(3, 'Swarm:NODEPUSH'); parent.debug('swarmcmd', 'NODEPUSH');
var nodeblock = obj.decodeNodeBlock(data); var nodeblock = obj.decodeNodeBlock(data);
if ((nodeblock != null) && (nodeblock.agenttype != null) && (nodeblock.agentversion != null)) { if ((nodeblock != null) && (nodeblock.agenttype != null) && (nodeblock.agentversion != null)) {
if (socket.pingTimer == null) { socket.pingTimer = setInterval(function () { obj.SendCommand(socket, LegacyMeshProtocol.PING); }, 20000); } if (socket.pingTimer == null) { socket.pingTimer = setInterval(function () { obj.SendCommand(socket, LegacyMeshProtocol.PING); }, 20000); }
Debug(3, 'Swarm:NODEPUSH:' + JSON.stringify(nodeblock)); parent.debug('swarmcmd', 'NODEPUSH:' + JSON.stringify(nodeblock));
// Log the agent type // Log the agent type
if (obj.stats.agenttype[nodeblock.agenttype] == null) { obj.stats.agenttype[nodeblock.agenttype] = 1; } else { obj.stats.agenttype[nodeblock.agenttype]++; } if (obj.stats.agenttype[nodeblock.agenttype] == null) { obj.stats.agenttype[nodeblock.agenttype] = 1; } else { obj.stats.agenttype[nodeblock.agenttype]++; }
@ -256,12 +256,12 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
break; break;
} }
case LegacyMeshProtocol.AMTPROVISIONING: { case LegacyMeshProtocol.AMTPROVISIONING: {
Debug(3, 'Swarm:AMTPROVISIONING'); parent.debug('swarmcmd', 'AMTPROVISIONING');
obj.SendCommand(socket, LegacyMeshProtocol.AMTPROVISIONING, common.ShortToStr(1)); obj.SendCommand(socket, LegacyMeshProtocol.AMTPROVISIONING, common.ShortToStr(1));
break; break;
} }
case LegacyMeshProtocol.GETSTATE: { case LegacyMeshProtocol.GETSTATE: {
Debug(3, 'Swarm:GETSTATE'); parent.debug('swarmcmd', 'GETSTATE');
if (len < 12) break; if (len < 12) break;
var statecmd = common.ReadInt(data, 0); var statecmd = common.ReadInt(data, 0);
//var statesync = common.ReadInt(data, 4); //var statesync = common.ReadInt(data, 4);
@ -272,13 +272,13 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
if (socket.tag.update.binary == null) { socket.tag.update.binary = obj.parent.fs.readFileSync(socket.tag.update.path); } if (socket.tag.update.binary == null) { socket.tag.update.binary = obj.parent.fs.readFileSync(socket.tag.update.path); }
var l = Math.min(socket.tag.update.binary.length - socket.tag.updatePtr, 16384); var l = Math.min(socket.tag.update.binary.length - socket.tag.updatePtr, 16384);
obj.SendCommand(socket, LegacyMeshProtocol.GETSTATE, common.IntToStr(6) + common.IntToStr(socket.tag.updatePtr) + socket.tag.update.binary.toString('binary', socket.tag.updatePtr, socket.tag.updatePtr + l)); // agent.SendQuery(6, AgentFileLen + AgentBlock); obj.SendCommand(socket, LegacyMeshProtocol.GETSTATE, common.IntToStr(6) + common.IntToStr(socket.tag.updatePtr) + socket.tag.update.binary.toString('binary', socket.tag.updatePtr, socket.tag.updatePtr + l)); // agent.SendQuery(6, AgentFileLen + AgentBlock);
Debug(3, 'Swarm:Sending agent block, ptr = ' + socket.tag.updatePtr + ', len = ' + l); parent.debug('swarmcmd', 'Sending agent block, ptr = ' + socket.tag.updatePtr + ', len = ' + l);
socket.tag.updatePtr += l; socket.tag.updatePtr += l;
if (socket.tag.updatePtr >= socket.tag.update.binary.length) { if (socket.tag.updatePtr >= socket.tag.update.binary.length) {
// Send end-of-transfer // Send end-of-transfer
obj.SendCommand(socket, LegacyMeshProtocol.GETSTATE, common.IntToStr(7) + common.IntToStr(socket.tag.update.binary.length)); //agent.SendQuery(7, AgentFileLen); obj.SendCommand(socket, LegacyMeshProtocol.GETSTATE, common.IntToStr(7) + common.IntToStr(socket.tag.update.binary.length)); //agent.SendQuery(7, AgentFileLen);
Debug(3, 'Swarm:Sending end of agent, ptr = ' + socket.tag.updatePtr); parent.debug('swarmcmd', 'Sending end of agent, ptr = ' + socket.tag.updatePtr);
obj.parent.taskLimiter.completed(socket.tag.taskid); // Indicate this task complete obj.parent.taskLimiter.completed(socket.tag.taskid); // Indicate this task complete
delete socket.tag.taskid; delete socket.tag.taskid;
delete socket.tag.update; delete socket.tag.update;
@ -295,11 +295,11 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
break; break;
} }
case LegacyMeshProtocol.APPSUBSCRIBERS: { case LegacyMeshProtocol.APPSUBSCRIBERS: {
Debug(3, 'Swarm:APPSUBSCRIBERS'); parent.debug('swarmcmd', 'APPSUBSCRIBERS');
break; break;
} }
default: { default: {
Debug(1, 'Swarm:Unknown command: ' + cmd + ' of len ' + len + '.'); parent.debug('swarmcmd', 'Unknown command: ' + cmd + ' of len ' + len + '.');
} }
} }
return len; return len;
@ -308,18 +308,18 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
// Called when a legacy agent connects to this server // Called when a legacy agent connects to this server
function onConnection(socket) { function onConnection(socket) {
// Check for blocked IP address // Check for blocked IP address
if (checkSwarmIpAddress(socket, obj.args.swarmallowedip) == false) { obj.stats.blockedConnect++; Debug(1, "SWARM:New blocked agent connection"); return; } if (checkSwarmIpAddress(socket, obj.args.swarmallowedip) == false) { obj.stats.blockedConnect++; parent.debug('swarm', "New blocked agent connection"); return; }
obj.stats.connectCount++; obj.stats.connectCount++;
socket.tag = { first: true, clientCert: socket.getPeerCertificate(true), accumulator: "" }; socket.tag = { first: true, clientCert: socket.getPeerCertificate(true), accumulator: "" };
Debug(1, 'SWARM:New legacy agent connection'); parent.debug('swarm', 'New legacy agent connection');
if ((socket.tag.clientCert == null) || (socket.tag.clientCert.subject == null)) { obj.stats.noCertConnectCount++; } else { obj.stats.clientCertConnectCount++; } if ((socket.tag.clientCert == null) || (socket.tag.clientCert.subject == null)) { obj.stats.noCertConnectCount++; } else { obj.stats.clientCertConnectCount++; }
socket.addListener("data", onData); socket.addListener("data", onData);
socket.addListener("close", function () { socket.addListener("close", function () {
obj.stats.onclose++; obj.stats.onclose++;
Debug(1, 'Swarm:Connection closed'); parent.debug('swarm', 'Connection closed');
// Perform aggressive cleanup // Perform aggressive cleanup
if (this.relaySocket) { try { this.relaySocket.end(); this.relaySocket.removeAllListeners(["data", "end", "error"]); delete this.relaySocket; } catch (ex) { } } if (this.relaySocket) { try { this.relaySocket.end(); this.relaySocket.removeAllListeners(["data", "end", "error"]); delete this.relaySocket; } catch (ex) { } }
@ -430,16 +430,5 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
return false; return false;
} }
// Debug
function Debug(lvl) {
if (lvl > obj.parent.debugLevel) return;
if (arguments.length == 2) { console.log(arguments[1]); }
else if (arguments.length == 3) { console.log(arguments[1], arguments[2]); }
else if (arguments.length == 4) { console.log(arguments[1], arguments[2], arguments[3]); }
else if (arguments.length == 5) { console.log(arguments[1], arguments[2], arguments[3], arguments[4]); }
else if (arguments.length == 6) { console.log(arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); }
else if (arguments.length == 7) { console.log(arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6]); }
}
return obj; return obj;
}; };

File diff suppressed because one or more lines are too long

View File

@ -148,6 +148,7 @@
<td tabindex=0 id=ServerGeneral class="topbar_td style3x" onclick=go(6) onkeypress="if (event.key == 'Enter') go(6)">General</td> <td tabindex=0 id=ServerGeneral class="topbar_td style3x" onclick=go(6) onkeypress="if (event.key == 'Enter') go(6)">General</td>
<td tabindex=0 id=ServerStats class="topbar_td style3x" onclick=go(40) onkeypress="if (event.key == 'Enter') go(40)">Stats</td> <td tabindex=0 id=ServerStats class="topbar_td style3x" onclick=go(40) onkeypress="if (event.key == 'Enter') go(40)">Stats</td>
<td tabindex=0 id=ServerConsole class="topbar_td style3x" onclick=go(115) onkeypress="if (event.key == 'Enter') go(115)">Console</td> <td tabindex=0 id=ServerConsole class="topbar_td style3x" onclick=go(115) onkeypress="if (event.key == 'Enter') go(115)">Console</td>
<td tabindex=0 id=ServerTrace class="topbar_td style3x" onclick=go(41) onkeypress="if (event.key == 'Enter') go(41)">Trace</td>
<td class="topbar_td_end style3">&nbsp;</td> <td class="topbar_td_end style3">&nbsp;</td>
</tr> </tr>
</table> </table>
@ -783,7 +784,7 @@
</table> </table>
<div id=p31events style=""></div> <div id=p31events style=""></div>
</div> </div>
<div id=p40 style="display:none;"> <div id=p40 style="display:none">
<h1>My Server Stats</h1> <h1>My Server Stats</h1>
<div class="areaHead"> <div class="areaHead">
<div class="toright2"> <div class="toright2">
@ -807,6 +808,27 @@
</div> </div>
<canvas id=serverMainStats style=""></canvas> <canvas id=serverMainStats style=""></canvas>
</div> </div>
<div id=p41 style="display:none">
<h1>My Server Tracing</h1>
<div class="areaHead">
<div class="toright2">
Show
<select id=p41limitdropdown onchange=displayServerTrace()>
<option value=100>Last 100</option>
<option value=250>Last 250</option>
<option value=500>Last 500</option>
<option value=1000>Last 1000</option>
</select>
<input value="Clear" type="button" onclick="clearServerTracing()" />
<img src=images/link4.png height=10 width=10 title="Download trace (.csv)" style=cursor:pointer onclick=p41downloadServerTrace()>&nbsp;
</div>
<div>
<input value="Tracing" type="button" onclick="setServerTracing()" />
<span id="p41traceStatus">None</span>
</div>
</div>
<div id=p41events style=""></div>
</div>
<br id="column_l_bottomgap" /> <br id="column_l_bottomgap" />
</div> </div>
<div id="footer"> <div id="footer">
@ -1283,6 +1305,7 @@
} }
meshserver.send({ action: 'events', limit: parseInt(p3limitdropdown.value) }); meshserver.send({ action: 'events', limit: parseInt(p3limitdropdown.value) });
QV('ServerConsole', userinfo.siteadmin === 0xFFFFFFFF); QV('ServerConsole', userinfo.siteadmin === 0xFFFFFFFF);
QV('ServerTrace', userinfo.siteadmin === 0xFFFFFFFF);
if ((xxcurrentView == 115) && (userinfo.siteadmin != 0xFFFFFFFF)) { go(6); } if ((xxcurrentView == 115) && (userinfo.siteadmin != 0xFFFFFFFF)) { go(6); }
if ((xxcurrentView == 6) && ((userinfo.siteadmin & 21) == 0)) { go(1); } if ((xxcurrentView == 6) && ((userinfo.siteadmin & 21) == 0)) { go(1); }
@ -1361,6 +1384,22 @@
function onMessage(server, message) { function onMessage(server, message) {
switch (message.action) { switch (message.action) {
case 'trace': {
serverTrace.unshift(message);
displayServerTrace();
break;
}
case 'traceinfo': {
if (typeof message.traceSources == 'object') {
serverTraceSources = message.traceSources;
if (message.traceSources.length > 0) {
QH('p41traceStatus', EscapeHtml(message.traceSources.join(', ')));
} else {
QH('p41traceStatus', 'None');
}
}
break;
}
case 'serverstats': { case 'serverstats': {
updateGeneralServerStats(message); updateGeneralServerStats(message);
break; break;
@ -2078,6 +2117,17 @@
addNotification(n); addNotification(n);
break; break;
} }
case 'traceinfo': {
if (typeof message.event.traceSources == 'object') {
serverTraceSources = message.event.traceSources;
if (message.event.traceSources.length > 0) {
QH('p41traceStatus', EscapeHtml(message.event.traceSources.join(', ')));
} else {
QH('p41traceStatus', 'None');
}
}
break;
}
case 'stopped': { // Server is stopping. case 'stopped': { // Server is stopping.
// Disconnect // Disconnect
//console.log(message.msg); //console.log(message.msg);
@ -8545,6 +8595,57 @@
saveAs(new Blob([csv], { type: "application/octet-stream" }), "ServerStats.csv"); saveAs(new Blob([csv], { type: "application/octet-stream" }), "ServerStats.csv");
} }
//
// My Server Tracing
//
var serverTrace = [];
var serverTraceSources = [];
function displayServerTrace() {
var x = '', max = parseInt(Q('p41limitdropdown').value);
if (serverTrace.length > max) { serverTrace.splice(max); }
for (var i in serverTrace) { x += '<div class=traceEvent>' + EscapeHtml(new Date(serverTrace[i].time).toLocaleTimeString()) + ' - <b>' + EscapeHtml(serverTrace[i].source.toUpperCase()) + '</b>: ' + EscapeHtml(serverTrace[i].args.join(', ')) + '</div>' }
QH('p41events', x);
}
function clearServerTracing() { serverTrace = []; displayServerTrace(); }
function setServerTracing() {
var x = '';
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>Core Server</b></div>';
x += "<div><label><input type=checkbox id=p41c1 " + ((serverTraceSources.indexOf('cookie') >= 0) ? 'checked' : '') + ">Cookie encoder</label></div>";
x += "<div><label><input type=checkbox id=p41c2 " + ((serverTraceSources.indexOf('dispatch') >= 0) ? 'checked' : '') + ">Message Dispatcher</label></div>";
x += "<div><label><input type=checkbox id=p41c3 " + ((serverTraceSources.indexOf('main') >= 0) ? 'checked' : '') + ">Main Server Messages</label></div>";
x += "<div><label><input type=checkbox id=p41c4 " + ((serverTraceSources.indexOf('peer') >= 0) ? 'checked' : '') + ">MeshCentral Server Peering</label></div>";
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>Web Server</b></div>';
x += "<div><label><input type=checkbox id=p41c5 " + ((serverTraceSources.indexOf('web') >= 0) ? 'checked' : '') + ">Web Server</label></div>";
x += "<div><label><input type=checkbox id=p41c6 " + ((serverTraceSources.indexOf('webrequest') >= 0) ? 'checked' : '') + ">Web Server Requests</label></div>";
x += "<div><label><input type=checkbox id=p41c7 " + ((serverTraceSources.indexOf('relay') >= 0) ? 'checked' : '') + ">Web Socket Relay</label></div>";
//x += "<div><label><input type=checkbox id=p41c8 " + ((serverTraceSources.indexOf('webrelaydata') >= 0) ? 'checked' : '') + ">Traffic Relay 2 Data</label></div>";
x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>Intel AMT</b></div>';
x += "<div><label><input type=checkbox id=p41c9 " + ((serverTraceSources.indexOf('webrelay') >= 0) ? 'checked' : '') + ">Connection Relay</label></div>";
x += "<div><label><input type=checkbox id=p41c10 " + ((serverTraceSources.indexOf('mps') >= 0) ? 'checked' : '') + ">CIRA Server</label></div>";
x += "<div><label><input type=checkbox id=p41c11 " + ((serverTraceSources.indexOf('mpscmd') >= 0) ? 'checked' : '') + ">CIRA Server Commands</label></div>";
//x += '<div style="width:100%;border-bottom:1px solid gray;margin-bottom:5px;margin-top:5px"><b>Legacy</b></div>';
//x += "<div><label><input type=checkbox id=p41c12 " + ((serverTraceSources.indexOf('swarm') >= 0) ? 'checked' : '') + ">Legacy Swarm Server</label></div>";
//x += "<div><label><input type=checkbox id=p41c13 " + ((serverTraceSources.indexOf('swarmcmd') >= 0) ? 'checked' : '') + ">Legacy Swarm Server Commands</label></div>";
setDialogMode(2, "Server Tracing", 7, setServerTracingEx, x);
}
function setServerTracingEx(b) {
var sources = [], allsources = ['cookie', 'dispatch', 'main', 'peer', 'web', 'webrequest', 'relay', 'webrelaydata', 'webrelay', 'mps', 'mpscmd', 'swarm', 'swarmcmd'];
if (b == 1) { for (var i = 1; i < 13; i++) { try { if (Q('p41c' + i).checked) { sources.push(allsources[i - 1]); } } catch (ex) { } } }
meshserver.send({ action: 'traceinfo', traceSources: sources });
}
function p41downloadServerTrace() {
var csv = "time, source, message\r\n";
for (var i in serverTrace) { csv += '\"' + new Date(serverTrace[i].time).toLocaleTimeString() + '\",\"' + serverTrace[i].source + '\",\"' + serverTrace[i].args.join(', ') + '\"\r\n'; }
saveAs(new Blob([csv], { type: "application/octet-stream" }), "servertrace.csv");
return false;
}
// //
// POPUP DIALOG // POPUP DIALOG
// //
@ -8608,7 +8709,7 @@
QV('uiMenu', false); QV('uiMenu', false);
// Edit this line when adding a new screen // Edit this line when adding a new screen
for (var i = 0; i < 41; i++) { QV('p' + i, i == x); } for (var i = 0; i < 42; i++) { QV('p' + i, i == x); }
xxcurrentView = x; xxcurrentView = x;
// Remove top bar selection // Remove top bar selection
@ -8666,8 +8767,8 @@
QV('UserDummyMenuSpan', (x < 10) && (x != 6) && webPageFullScreen); QV('UserDummyMenuSpan', (x < 10) && (x != 6) && webPageFullScreen);
QV('MeshSubMenuSpan', x >= 20 && x < 30); QV('MeshSubMenuSpan', x >= 20 && x < 30);
QV('UserSubMenuSpan', x >= 30 && x < 40); QV('UserSubMenuSpan', x >= 30 && x < 40);
QV('ServerSubMenuSpan', x == 6 || x == 115 || x == 40); QV('ServerSubMenuSpan', x == 6 || x == 115 || x == 40 || x == 41);
var panels = { 10: 'MainDev', 11: 'MainDevDesktop', 12: 'MainDevTerminal', 13: 'MainDevFiles', 14: 'MainDevAmt', 15: 'MainDevConsole', 16: 'MainDevEvents', 20: 'MeshGeneral', 30: 'UserGeneral', 31: 'UserEvents', 6: 'ServerGeneral', 40: 'ServerStats', 115: 'ServerConsole' }; var panels = { 10: 'MainDev', 11: 'MainDevDesktop', 12: 'MainDevTerminal', 13: 'MainDevFiles', 14: 'MainDevAmt', 15: 'MainDevConsole', 16: 'MainDevEvents', 20: 'MeshGeneral', 30: 'UserGeneral', 31: 'UserEvents', 6: 'ServerGeneral', 40: 'ServerStats', 41: 'ServerTrace', 115: 'ServerConsole' };
for (var i in panels) { for (var i in panels) {
QC(panels[i]).remove('style3x'); QC(panels[i]).remove('style3x');
QC(panels[i]).remove('style3sel'); QC(panels[i]).remove('style3sel');

File diff suppressed because one or more lines are too long

View File

@ -1471,10 +1471,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
} }
// Return true if it looks like we are using a real TLS certificate. // Return true if it looks like we are using a real TLS certificate.
function isTrustedCert() { function isTrustedCert(domain) {
if (obj.args.notls == true) return false; // We are not using TLS, so not trusted cert. if (obj.args.notls == true) return false; // We are not using TLS, so not trusted cert.
if ((domain != null) && (typeof domain.trustedcert == 'boolean')) return domain.trustedcert; // If the status of the cert specified, use that.
if (typeof obj.args.trustedcert == 'boolean') return obj.args.trustedcert; // If the status of the cert specified, use that.
if (obj.args.tlsoffload != null) return true; // We are using TLS offload, a real cert is likely used. if (obj.args.tlsoffload != null) return true; // We are using TLS offload, a real cert is likely used.
if (obj.parent.config.letsencrypt != null) return true; // We are using Let's Encrypt, real cert in use. if (obj.parent.config.letsencrypt != null) return (obj.parent.config.letsencrypt.production === true); // We are using Let's Encrypt, real cert in use if production is set to true.
if (obj.certificates.WebIssuer.indexOf('MeshCentralRoot-') == 0) return false; // Our cert is issued by self-signed cert. if (obj.certificates.WebIssuer.indexOf('MeshCentralRoot-') == 0) return false; // Our cert is issued by self-signed cert.
if (obj.certificates.CommonName.indexOf('.') == -1) return false; // Our cert is named with a fake name if (obj.certificates.CommonName.indexOf('.') == -1) return false; // Our cert is named with a fake name
return true; // This is a guess return true; // This is a guess
@ -1920,7 +1922,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Handle a web socket relay request // Handle a web socket relay request
function handleRelayWebSocket(ws, req, domain, user, cookie) { function handleRelayWebSocket(ws, req, domain, user, cookie) {
if (!(req.query.host)) { console.log('ERR: No host target specified'); try { ws.close(); } catch (e) { } return; } // Disconnect websocket if (!(req.query.host)) { console.log('ERR: No host target specified'); try { ws.close(); } catch (e) { } return; } // Disconnect websocket
Debug(1, 'Websocket relay connected from ' + user.name + ' for ' + req.query.host + '.'); parent.debug('web', 'Websocket relay connected from ' + user.name + ' for ' + req.query.host + '.');
try { ws._socket.setKeepAlive(true, 240000); } catch (ex) { } // Set TCP keep alive try { ws._socket.setKeepAlive(true, 240000); } catch (ex) { } // Set TCP keep alive
@ -1937,7 +1939,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Check what connectivity is available for this node // Check what connectivity is available for this node
var state = parent.GetConnectivityState(req.query.host); var state = parent.GetConnectivityState(req.query.host);
var conn = 0; var conn = 0;
if (!state || state.connectivity == 0) { Debug(1, 'ERR: No routing possible (1)'); try { ws.close(); } catch (e) { } return; } else { conn = state.connectivity; } if (!state || state.connectivity == 0) { parent.debug('web', 'ERR: No routing possible (1)'); try { ws.close(); } catch (e) { } return; } else { conn = state.connectivity; }
// Check what server needs to handle this connection // Check what server needs to handle this connection
if ((obj.parent.multiServer != null) && ((cookie == null) || (cookie.ps != 1))) { // If a cookie is provided and is from a peer server, don't allow the connection to jump again to a different server if ((obj.parent.multiServer != null) && ((cookie == null) || (cookie.ps != 1))) { // If a cookie is provided and is from a peer server, don't allow the connection to jump again to a different server
@ -1945,7 +1947,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (server != null) { if (server != null) {
if (server.serverid != obj.parent.serverId) { if (server.serverid != obj.parent.serverId) {
// Do local Intel CIRA routing using a different server // Do local Intel CIRA routing using a different server
Debug(1, 'Route Intel AMT CIRA connection to peer server: ' + server.serverid); parent.debug('web', 'Route Intel AMT CIRA connection to peer server: ' + server.serverid);
obj.parent.multiServer.createPeerRelay(ws, req, server.serverid, user); obj.parent.multiServer.createPeerRelay(ws, req, server.serverid, user);
return; return;
} }
@ -1953,7 +1955,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
server = obj.parent.GetRoutingServerId(req.query.host, 4); // Check for local Intel AMT connection server = obj.parent.GetRoutingServerId(req.query.host, 4); // Check for local Intel AMT connection
if ((server != null) && (server.serverid != obj.parent.serverId)) { if ((server != null) && (server.serverid != obj.parent.serverId)) {
// Do local Intel AMT routing using a different server // Do local Intel AMT routing using a different server
Debug(1, 'Route Intel AMT direct connection to peer server: ' + server.serverid); parent.debug('web', 'Route Intel AMT direct connection to peer server: ' + server.serverid);
obj.parent.multiServer.createPeerRelay(ws, req, server.serverid, user); obj.parent.multiServer.createPeerRelay(ws, req, server.serverid, user);
return; return;
} }
@ -1984,7 +1986,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// If Intel AMT CIRA connection is available, use it // If Intel AMT CIRA connection is available, use it
if (((conn & 2) != 0) && (parent.mpsserver.ciraConnections[req.query.host] != null)) { if (((conn & 2) != 0) && (parent.mpsserver.ciraConnections[req.query.host] != null)) {
Debug(1, 'Opening relay CIRA channel connection to ' + req.query.host + '.'); parent.debug('web', 'Opening relay CIRA channel connection to ' + req.query.host + '.');
var ciraconn = parent.mpsserver.ciraConnections[req.query.host]; var ciraconn = parent.mpsserver.ciraConnections[req.query.host];
@ -2010,13 +2012,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// When APF tunnel return something, update SerialTunnel buffer // When APF tunnel return something, update SerialTunnel buffer
chnl.onData = function (ciraconn, data) { chnl.onData = function (ciraconn, data) {
// CIRA ---> TLS // CIRA ---> TLS
Debug(3, 'Relay TLS CIRA data', data.length); parent.debug('webrelay', 'Relay TLS CIRA data', data.length);
if (data.length > 0) { try { ser.updateBuffer(Buffer.from(data, 'binary')); } catch (e) { } } if (data.length > 0) { try { ser.updateBuffer(Buffer.from(data, 'binary')); } catch (e) { } }
}; };
// Handle CIRA tunnel state change // Handle CIRA tunnel state change
chnl.onStateChange = function (ciraconn, state) { chnl.onStateChange = function (ciraconn, state) {
Debug(2, 'Relay TLS CIRA state change', state); parent.debug('webrelay', 'Relay TLS CIRA state change', state);
if (state == 0) { try { ws.close(); } catch (e) { } } if (state == 0) { try { ws.close(); } catch (e) { } }
}; };
@ -2024,8 +2026,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
const TLSSocket = require('tls').TLSSocket; const TLSSocket = require('tls').TLSSocket;
const tlsoptions = { secureProtocol: ((req.query.tls1only == 1) ? 'TLSv1_method' : 'SSLv23_method'), ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false }; const tlsoptions = { secureProtocol: ((req.query.tls1only == 1) ? 'TLSv1_method' : 'SSLv23_method'), ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false };
const tlsock = new TLSSocket(ser, tlsoptions); const tlsock = new TLSSocket(ser, tlsoptions);
tlsock.on('error', function (err) { Debug(1, "CIRA TLS Connection Error ", err); }); tlsock.on('error', function (err) { parent.debug('webrelay', "CIRA TLS Connection Error ", err); });
tlsock.on('secureConnect', function () { Debug(2, "CIRA Secure TLS Connection"); ws._socket.resume(); }); tlsock.on('secureConnect', function () { parent.debug('webrelay', "CIRA Secure TLS Connection"); ws._socket.resume(); });
// Decrypted tunnel from TLS communcation to be forwarded to websocket // Decrypted tunnel from TLS communcation to be forwarded to websocket
tlsock.on('data', function (data) { tlsock.on('data', function (data) {
@ -2070,7 +2072,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// If error, close the associated TCP connection. // If error, close the associated TCP connection.
ws.on('error', function (err) { ws.on('error', function (err) {
console.log('CIRA server websocket error from ' + ws._socket.remoteAddress + ', ' + err.toString().split('\r')[0] + '.'); console.log('CIRA server websocket error from ' + ws._socket.remoteAddress + ', ' + err.toString().split('\r')[0] + '.');
Debug(1, 'Websocket relay closed on error.'); parent.debug('webrelay', 'Websocket relay closed on error.');
if (ws.forwardclient && ws.forwardclient.close) { ws.forwardclient.close(); } // TODO: If TLS is used, we need to close the socket that is wrapped by TLS if (ws.forwardclient && ws.forwardclient.close) { ws.forwardclient.close(); } // TODO: If TLS is used, we need to close the socket that is wrapped by TLS
// Close the recording file // Close the recording file
@ -2084,7 +2086,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// If the web socket is closed, close the associated TCP connection. // If the web socket is closed, close the associated TCP connection.
ws.on('close', function (req) { ws.on('close', function (req) {
Debug(1, 'Websocket relay closed.'); parent.debug('webrelay', 'Websocket relay closed.');
if (ws.forwardclient && ws.forwardclient.close) { ws.forwardclient.close(); } // TODO: If TLS is used, we need to close the socket that is wrapped by TLS if (ws.forwardclient && ws.forwardclient.close) { ws.forwardclient.close(); } // TODO: If TLS is used, we need to close the socket that is wrapped by TLS
// Close the recording file // Close the recording file
@ -2097,12 +2099,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
}); });
ws.forwardclient.onStateChange = function (ciraconn, state) { ws.forwardclient.onStateChange = function (ciraconn, state) {
Debug(2, 'Relay CIRA state change', state); parent.debug('webrelay', 'Relay CIRA state change', state);
if (state == 0) { try { ws.close(); } catch (e) { } } if (state == 0) { try { ws.close(); } catch (e) { } }
}; };
ws.forwardclient.onData = function (ciraconn, data) { ws.forwardclient.onData = function (ciraconn, data) {
Debug(4, 'Relay CIRA data', data.length); parent.debug('webrelaydata', 'Relay CIRA data', data.length);
if (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor if (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor
//console.log('AMT --> WS', Buffer.from(data, 'binary').toString('hex')); //console.log('AMT --> WS', Buffer.from(data, 'binary').toString('hex'));
if (data.length > 0) { if (data.length > 0) {
@ -2123,12 +2125,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Fetch Intel AMT credentials & Setup interceptor // Fetch Intel AMT credentials & Setup interceptor
if (req.query.p == 1) { if (req.query.p == 1) {
Debug(3, 'INTERCEPTOR1', { host: node.host, port: port, user: node.intelamt.user, pass: node.intelamt.pass }); parent.debug('webrelaydata', 'INTERCEPTOR1', { host: node.host, port: port, user: node.intelamt.user, pass: node.intelamt.pass });
ws.interceptor = obj.interceptor.CreateHttpInterceptor({ host: node.host, port: port, user: node.intelamt.user, pass: node.intelamt.pass }); ws.interceptor = obj.interceptor.CreateHttpInterceptor({ host: node.host, port: port, user: node.intelamt.user, pass: node.intelamt.pass });
ws.interceptor.blockAmtStorage = true; ws.interceptor.blockAmtStorage = true;
} }
else if (req.query.p == 2) { else if (req.query.p == 2) {
Debug(3, 'INTERCEPTOR2', { user: node.intelamt.user, pass: node.intelamt.pass }); parent.debug('webrelaydata', 'INTERCEPTOR2', { user: node.intelamt.user, pass: node.intelamt.pass });
ws.interceptor = obj.interceptor.CreateRedirInterceptor({ user: node.intelamt.user, pass: node.intelamt.pass }); ws.interceptor = obj.interceptor.CreateRedirInterceptor({ user: node.intelamt.user, pass: node.intelamt.pass });
ws.interceptor.blockAmtStorage = true; ws.interceptor.blockAmtStorage = true;
} }
@ -2138,13 +2140,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// If Intel AMT direct connection is possible, option a direct socket // 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. if ((conn & 4) != 0) { // We got a new web socket connection, initiate a TCP connection to the target Intel AMT host/port.
Debug(1, 'Opening relay TCP socket connection to ' + req.query.host + '.'); 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. // When data is received from the web socket, forward the data into the associated TCP connection.
ws.on('message', function (msg) { ws.on('message', function (msg) {
if (obj.parent.debugLevel >= 1) { // DEBUG if (obj.parent.debugLevel >= 1) { // DEBUG
Debug(2, 'TCP relay data to ' + node.host + ', ' + msg.length + ' bytes'); parent.debug('webrelaydata', 'TCP relay data to ' + node.host + ', ' + msg.length + ' bytes');
if (obj.parent.debugLevel >= 4) { Debug(4, ' ' + msg.toString('hex')); } //if (obj.parent.debugLevel >= 4) { parent.debug('webrelaydatahex', ' ' + msg.toString('hex')); }
} }
msg = msg.toString('binary'); msg = msg.toString('binary');
if (ws.interceptor) { msg = ws.interceptor.processBrowserData(msg); } // Run data thru interceptor if (ws.interceptor) { msg = ws.interceptor.processBrowserData(msg); } // Run data thru interceptor
@ -2163,7 +2165,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// If error, close the associated TCP connection. // If error, close the associated TCP connection.
ws.on('error', function (err) { ws.on('error', function (err) {
console.log('Error with relay web socket connection from ' + ws._socket.remoteAddress + ', ' + err.toString().split('\r')[0] + '.'); console.log('Error with relay web socket connection from ' + ws._socket.remoteAddress + ', ' + err.toString().split('\r')[0] + '.');
Debug(1, 'Error with relay web socket connection from ' + ws._socket.remoteAddress + '.'); parent.debug('webrelay', 'Error with relay web socket connection from ' + ws._socket.remoteAddress + '.');
if (ws.forwardclient) { try { ws.forwardclient.destroy(); } catch (e) { } } if (ws.forwardclient) { try { ws.forwardclient.destroy(); } catch (e) { } }
// Close the recording file // Close the recording file
@ -2177,7 +2179,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// If the web socket is closed, close the associated TCP connection. // If the web socket is closed, close the associated TCP connection.
ws.on('close', function () { ws.on('close', function () {
Debug(1, 'Closing relay web socket connection to ' + req.query.host + '.'); parent.debug('webrelay', 'Closing relay web socket connection to ' + req.query.host + '.');
if (ws.forwardclient) { try { ws.forwardclient.destroy(); } catch (e) { } } if (ws.forwardclient) { try { ws.forwardclient.destroy(); } catch (e) { } }
// Close the recording file // Close the recording file
@ -2206,7 +2208,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
var tlsoptions = { secureProtocol: ((req.query.tls1only == 1) ? 'TLSv1_method' : 'SSLv23_method'), ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false }; var tlsoptions = { secureProtocol: ((req.query.tls1only == 1) ? 'TLSv1_method' : 'SSLv23_method'), ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false };
ws.forwardclient = obj.tls.connect(port, node.host, tlsoptions, function () { ws.forwardclient = obj.tls.connect(port, node.host, tlsoptions, function () {
// The TLS connection method is the same as TCP, but located a bit differently. // The TLS connection method is the same as TCP, but located a bit differently.
Debug(2, 'TLS connected to ' + node.host + ':' + port + '.'); parent.debug('webrelay', 'TLS connected to ' + node.host + ':' + port + '.');
ws.forwardclient.xstate = 1; ws.forwardclient.xstate = 1;
ws._socket.resume(); ws._socket.resume();
}); });
@ -2218,8 +2220,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// When we receive data on the TCP connection, forward it back into the web socket connection. // When we receive data on the TCP connection, forward it back into the web socket connection.
ws.forwardclient.on('data', function (data) { ws.forwardclient.on('data', function (data) {
if (obj.parent.debugLevel >= 1) { // DEBUG if (obj.parent.debugLevel >= 1) { // DEBUG
Debug(2, 'TCP relay data from ' + node.host + ', ' + data.length + ' bytes.'); parent.debug('webrelaydata', 'TCP relay data from ' + node.host + ', ' + data.length + ' bytes.');
if (obj.parent.debugLevel >= 4) { Debug(4, ' ' + Buffer.from(data, 'binary').toString('hex')); } //if (obj.parent.debugLevel >= 4) { Debug(4, ' ' + Buffer.from(data, 'binary').toString('hex')); }
} }
if (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor if (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor
if (ws.logfile == null) { if (ws.logfile == null) {
@ -2234,13 +2236,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// If the TCP connection closes, disconnect the associated web socket. // If the TCP connection closes, disconnect the associated web socket.
ws.forwardclient.on('close', function () { ws.forwardclient.on('close', function () {
Debug(1, 'TCP relay disconnected from ' + node.host + '.'); parent.debug('webrelay', 'TCP relay disconnected from ' + node.host + '.');
try { ws.close(); } catch (e) { } try { ws.close(); } catch (e) { }
}); });
// If the TCP connection causes an error, disconnect the associated web socket. // If the TCP connection causes an error, disconnect the associated web socket.
ws.forwardclient.on('error', function (err) { ws.forwardclient.on('error', function (err) {
Debug(1, 'TCP relay error from ' + node.host + ': ' + err.errno); parent.debug('webrelay', 'TCP relay error from ' + node.host + ': ' + err.errno);
try { ws.close(); } catch (e) { } try { ws.close(); } catch (e) { }
}); });
@ -2251,7 +2253,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (node.intelamt.tls == 0) { if (node.intelamt.tls == 0) {
// A TCP connection to Intel AMT just connected, start forwarding. // A TCP connection to Intel AMT just connected, start forwarding.
ws.forwardclient.connect(port, node.host, function () { ws.forwardclient.connect(port, node.host, function () {
Debug(1, 'TCP relay connected to ' + node.host + ':' + port + '.'); parent.debug('webrelay', 'TCP relay connected to ' + node.host + ':' + port + '.');
ws.forwardclient.xstate = 1; ws.forwardclient.xstate = 1;
ws._socket.resume(); ws._socket.resume();
}); });
@ -2677,7 +2679,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'text/plain', 'Content-Disposition': 'attachment; filename="' + scriptInfo.rname + '"' }); res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'text/plain', 'Content-Disposition': 'attachment; filename="' + scriptInfo.rname + '"' });
var data = scriptInfo.data; var data = scriptInfo.data;
var cmdoptions = { wgetoptionshttp: '', wgetoptionshttps: '', curloptionshttp: '-L ', curloptionshttps: '-L ' } var cmdoptions = { wgetoptionshttp: '', wgetoptionshttps: '', curloptionshttp: '-L ', curloptionshttps: '-L ' }
if (isTrustedCert() != true) { if (isTrustedCert(domain) != true) {
cmdoptions.wgetoptionshttps += '--no-check-certificate '; cmdoptions.wgetoptionshttps += '--no-check-certificate ';
cmdoptions.curloptionshttps += '-k '; cmdoptions.curloptionshttps += '-k ';
} }
@ -2989,11 +2991,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
keys: [obj.args.sessionkey], // If multiple instances of this server are behind a load-balancer, this secret must be the same for all instances keys: [obj.args.sessionkey], // If multiple instances of this server are behind a load-balancer, this secret must be the same for all instances
secure: (obj.args.notls != true) // Use this cookie only over TLS (Check this: https://expressjs.com/en/guide/behind-proxies.html) secure: (obj.args.notls != true) // Use this cookie only over TLS (Check this: https://expressjs.com/en/guide/behind-proxies.html)
} }
if (obj.args.sessionsamesite != null) { sessionOptions.sameSite = obj.args.sessionsamesite; }
if (obj.args.sessiontime != null) { sessionOptions.maxAge = (obj.args.sessiontime * 60 * 1000); } if (obj.args.sessiontime != null) { sessionOptions.maxAge = (obj.args.sessiontime * 60 * 1000); }
obj.app.use(obj.session(sessionOptions)); obj.app.use(obj.session(sessionOptions));
// Add HTTP security headers to all responses // Add HTTP security headers to all responses
obj.app.use(function (req, res, next) { obj.app.use(function (req, res, next) {
parent.debug('webrequest', req.url);
res.removeHeader("X-Powered-By"); res.removeHeader("X-Powered-By");
var domain = req.xdomain = getDomain(req); var domain = req.xdomain = getDomain(req);
@ -3086,7 +3090,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Receive mesh agent connections // Receive mesh agent connections
obj.app.ws(url + 'agent.ashx', function (ws, req) { obj.app.ws(url + 'agent.ashx', function (ws, req) {
var domain = checkAgentIpAddress(ws, req); var domain = checkAgentIpAddress(ws, req);
if (domain == null) { Debug(1, 'Got agent connection from blocked IP address ' + ws._socket.remoteAddress + ', holding.'); return; } if (domain == null) { parent.debug('web', 'Got agent connection from blocked IP address ' + ws._socket.remoteAddress + ', holding.'); return; }
// console.log('Agent connect: ' + ws._socket.remoteAddress); // console.log('Agent connect: ' + ws._socket.remoteAddress);
try { obj.meshAgentHandler.CreateMeshAgent(obj, obj.db, ws, req, obj.args, domain); } catch (e) { console.log(e); } try { obj.meshAgentHandler.CreateMeshAgent(obj, obj.db, ws, req, obj.args, domain); } catch (e) { console.log(e); }
}); });
@ -3128,10 +3132,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
obj.app.use(url, obj.express.static(obj.parent.webPublicPath)); obj.app.use(url, obj.express.static(obj.parent.webPublicPath));
// Handle 404 error // Handle 404 error
obj.app.use(function (req, res, next) { if (obj.args.nice404 !== false) {
var domain = getDomain(req); obj.app.use(function (req, res, next) {
res.status(404).render(obj.path.join(obj.parent.webViewsPath, isMobileBrowser(req) ? 'error404-mobile' : 'error404'), { title: domain.title, title2: domain.title2 }); parent.debug('web', '404 Error ' + req.url);
}) var domain = getDomain(req);
res.status(404).render(obj.path.join(obj.parent.webViewsPath, isMobileBrowser(req) ? 'error404-mobile' : 'error404'), { title: domain.title, title2: domain.title2 });
});
}
// Start regular disconnection list flush every 2 minutes. // Start regular disconnection list flush every 2 minutes.
obj.wsagentsDisconnectionsTimer = setInterval(function () { obj.wsagentsDisconnections = {}; }, 120000); obj.wsagentsDisconnectionsTimer = setInterval(function () { obj.wsagentsDisconnections = {}; }, 120000);
@ -3183,7 +3190,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
func(ws, req, domain, obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]); func(ws, req, domain, obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]);
} else { } else {
// If not authenticated, close the websocket connection // If not authenticated, close the websocket connection
Debug(1, 'ERR: Websocket bad user/pass auth'); parent.debug('web', 'ERR: Websocket bad user/pass auth');
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth-2' })); ws.close(); } catch (e) { } try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth-2' })); ws.close(); } catch (e) { }
} }
} }
@ -3198,7 +3205,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
func(ws, req, domain, obj.users[cookie.userid], cookie); func(ws, req, domain, obj.users[cookie.userid], cookie);
} else { } else {
// This is a bad cookie, keep going anyway, maybe we have a active session that will save us. // This is a bad cookie, keep going anyway, maybe we have a active session that will save us.
Debug(1, 'ERR: Websocket bad cookie auth: ' + req.query.auth); parent.debug('web', 'ERR: Websocket bad cookie auth: ' + req.query.auth);
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth-2' })); ws.close(); } catch (e) { } try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth-2' })); ws.close(); } catch (e) { }
} }
return; return;
@ -3235,7 +3242,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
func(ws, req, domain, obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]); func(ws, req, domain, obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]);
} else { } else {
// If not authenticated, close the websocket connection // If not authenticated, close the websocket connection
Debug(1, 'ERR: Websocket bad user/pass auth'); parent.debug('web', 'ERR: Websocket bad user/pass auth');
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth-2' })); ws.close(); } catch (e) { } try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth-2' })); ws.close(); } catch (e) { }
} }
} }
@ -3257,7 +3264,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (noAuthOk != true) { if (noAuthOk != true) {
// If not authenticated, close the websocket connection // If not authenticated, close the websocket connection
Debug(1, 'ERR: Websocket no auth'); parent.debug('web', 'ERR: Websocket no auth');
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth-4' })); ws.close(); } catch (e) { } try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth', msg: 'noauth-4' })); ws.close(); } catch (e) { }
} else { } else {
// Continue this session without user authentication, // Continue this session without user authentication,
@ -3359,17 +3366,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
return ok; return ok;
} }
// Debug
function Debug(lvl) {
if (lvl > obj.parent.debugLevel) return;
if (arguments.length == 2) { console.log(arguments[1]); }
else if (arguments.length == 3) { console.log(arguments[1], arguments[2]); }
else if (arguments.length == 4) { console.log(arguments[1], arguments[2], arguments[3]); }
else if (arguments.length == 5) { console.log(arguments[1], arguments[2], arguments[3], arguments[4]); }
else if (arguments.length == 6) { console.log(arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); }
else if (arguments.length == 7) { console.log(arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6]); }
}
/* /*
obj.wssessions = {}; // UserId --> Array Of Sessions obj.wssessions = {}; // UserId --> Array Of Sessions
obj.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd) obj.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd)