mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-12-24 06:05:53 -05:00
Added server tracing dialog in web app.
This commit is contained in:
parent
8efe4a3ebe
commit
dc193fde02
20
meshagent.js
20
meshagent.js
@ -45,8 +45,8 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
// Disconnect this agent
|
||||
obj.close = function (arg) {
|
||||
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 == 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 == 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('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).
|
||||
|
||||
// Remove this agent from the webserver list
|
||||
@ -166,11 +166,11 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
// Clear the core
|
||||
obj.sendBinary(common.ShortToStr(10) + common.ShortToStr(0)); // MeshCommand_CoreModule, ask mesh agent to clear the core
|
||||
parent.agentStats.clearingCoreCount++;
|
||||
parent.parent.debug(1, 'Clearing core');
|
||||
parent.parent.debug('agent', 'Clearing core');
|
||||
} else {
|
||||
// Update new core
|
||||
//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.
|
||||
obj.agentCoreUpdatePending = true;
|
||||
@ -180,7 +180,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
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
|
||||
parent.agentStats.updatingCoreCount++;
|
||||
parent.parent.debug(1, 'Updating core ' + argument.name);
|
||||
parent.parent.debug('agent', 'Updating core ' + argument.name);
|
||||
agentCoreIsStable();
|
||||
} else {
|
||||
// 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.
|
||||
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.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++;
|
||||
if (obj.agentExeInfo.data == null) {
|
||||
// Read the agent from disk
|
||||
@ -448,7 +448,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
//console.log('MeshID', obj.meshid);
|
||||
obj.agentInfo.capabilities = common.ReadInt(msg, 66);
|
||||
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;
|
||||
completeAgentConnection();
|
||||
} else if (cmd == 4) {
|
||||
@ -471,7 +471,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
if (obj.nodeid != null) {
|
||||
const agentId = (obj.agentInfo && obj.agentInfo.agentId) ? obj.agentInfo.agentId : 'Unknown';
|
||||
//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
|
||||
if (parent.wsagentsDisconnections[obj.nodeid] == null) {
|
||||
@ -765,7 +765,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
|
||||
// Close the duplicate agent
|
||||
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);
|
||||
} else {
|
||||
// Indicate the agent is connected
|
||||
@ -1034,7 +1034,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
delete obj.receivedCommands;
|
||||
if (obj.unauthsign) delete obj.unauthsign;
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
|
@ -44,7 +44,8 @@ function CreateMeshCentralServer(config, args) {
|
||||
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.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.dbconfig = {}; // Persistance values, loaded from database
|
||||
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.
|
||||
|
||||
// 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; } }
|
||||
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.
|
||||
@ -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.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.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,
|
||||
function (db) {
|
||||
obj.db = db;
|
||||
@ -896,7 +906,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
obj.DispatchEvent(['*'], obj, { action: 'servertimelinestats', data: data }); // Event the server stats
|
||||
}, 300000);
|
||||
|
||||
//obj.debug(1, 'Server started');
|
||||
obj.debug('main', 'Server started');
|
||||
if (obj.args.nousers == true) { obj.updateServerState('nousers', '1'); }
|
||||
obj.updateServerState('state', 'running');
|
||||
|
||||
@ -940,7 +950,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
// 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.
|
||||
if (restoreFile) {
|
||||
obj.debug(1, 'Server stopped, updating settings: ' + restoreFile);
|
||||
obj.debug('main', 'Server stopped, updating settings: ' + restoreFile);
|
||||
console.log('Updating settings folder...');
|
||||
|
||||
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); }); });
|
||||
});
|
||||
} else {
|
||||
obj.debug(1, 'Server stopped');
|
||||
obj.debug('main', 'Server stopped');
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
@ -977,26 +987,26 @@ function CreateMeshCentralServer(config, args) {
|
||||
|
||||
// Event Dispatch
|
||||
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); } }
|
||||
};
|
||||
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); } } } }
|
||||
};
|
||||
obj.RemoveEventDispatchId = function (id) {
|
||||
obj.debug(3, 'RemoveEventDispatchId', id);
|
||||
obj.debug('dispatch', 'RemoveEventDispatchId', id);
|
||||
if (obj.eventsDispatch[id] != null) { delete obj.eventsDispatch[id]; }
|
||||
};
|
||||
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); } } }
|
||||
};
|
||||
obj.DispatchEvent = function (ids, source, event, fromPeerServer) {
|
||||
// If the database is not setup, exit now.
|
||||
if (!obj.db) return;
|
||||
|
||||
obj.debug(3, 'DispatchEvent', ids);
|
||||
obj.debug('dispatch', 'DispatchEvent', ids);
|
||||
if ((typeof event == 'object') && (!event.nolog)) {
|
||||
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.
|
||||
@ -1340,7 +1350,7 @@ function CreateMeshCentralServer(config, args) {
|
||||
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.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
|
||||
//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));
|
||||
decipher.setAuthTag(cookie.slice(12, 16));
|
||||
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.dtime = Date.now() - o.time; // Decode how long ago the cookie was created (in milliseconds)
|
||||
if ((o.expire) == null || (typeof o.expire != 'number')) {
|
||||
// Use a fixed cookie expire time
|
||||
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 {
|
||||
// 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;
|
||||
} 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)
|
||||
@ -1611,28 +1621,38 @@ function CreateMeshCentralServer(config, args) {
|
||||
hmac.update(rawmsg.slice(48));
|
||||
if (Buffer.compare(hmac.digest(), Buffer.from(rawmsg.slice(0, 48))) == false) { return null; }
|
||||
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.dtime = Date.now() - o.time; // Decode how long ago the cookie was created (in milliseconds)
|
||||
if ((o.expire) == null || (typeof o.expire != 'number')) {
|
||||
// Use a fixed cookie expire time
|
||||
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 {
|
||||
// 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;
|
||||
} 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
|
||||
obj.debug = function (lvl) {
|
||||
if (lvl > obj.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]); }
|
||||
obj.debug = function (source, ...args) {
|
||||
// Send event to console
|
||||
if ((obj.debugSources != null) && ((obj.debugSources == '*') || (obj.debugSources.indexOf(source) >= 0))) { console.log(source.toUpperCase() + ':', ...args); }
|
||||
|
||||
// Send the event to logged in administrators
|
||||
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.
|
||||
|
28
meshrelay.js
28
meshrelay.js
@ -48,8 +48,8 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
|
||||
|
||||
// Disconnect this agent
|
||||
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 == 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 == 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('relay', 'Relay: Hard disconnect (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); } catch (e) { console.log(e); } } // Hard close, close the TCP socket
|
||||
|
||||
// Aggressive cleanup
|
||||
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
|
||||
if ((obj.authenticated != true) && (relayinfo.peer1.authenticated != true)) {
|
||||
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.ws;
|
||||
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) { }
|
||||
}
|
||||
|
||||
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
|
||||
if (sessionUser != null) {
|
||||
@ -214,7 +214,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
|
||||
} else {
|
||||
// Connected already, drop (TODO: maybe we should re-connect?)
|
||||
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.ws;
|
||||
delete obj.peer;
|
||||
@ -224,7 +224,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
|
||||
// Wait for other relay connection
|
||||
ws._socket.pause(); // Hold traffic until the other connection
|
||||
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
|
||||
if (parent.parent.multiServer != null) {
|
||||
@ -290,7 +290,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
|
||||
|
||||
// Disconnect the peer
|
||||
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._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.peer;
|
||||
} 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) { }
|
||||
delete parent.wsrelays[obj.id];
|
||||
@ -370,8 +370,8 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
|
||||
// Send connection request to agent
|
||||
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 };
|
||||
parent.parent.debug(1, '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) + ')'); }
|
||||
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('relay', 'Relay: Unable to contact this agent (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); }
|
||||
performRelay();
|
||||
});
|
||||
return obj;
|
||||
@ -390,12 +390,12 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
|
||||
|
||||
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) };
|
||||
parent.parent.debug(1, '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) + ')'); }
|
||||
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('relay', 'Relay: Unable to contact this agent (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); }
|
||||
} 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) };
|
||||
parent.parent.debug(1, '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) + ')'); }
|
||||
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('relay', 'Relay: Unable to contact this agent (' + cleanRemoteAddr(ws._socket.remoteAddress) + ')'); }
|
||||
}
|
||||
performRelay();
|
||||
});
|
||||
|
16
meshuser.js
16
meshuser.js
@ -53,8 +53,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
|
||||
// Disconnect this user
|
||||
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 == 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 == 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('user', 'Hard disconnect'); } catch (e) { console.log(e); } } // Hard close, close the TCP socket
|
||||
|
||||
// Perform cleanup
|
||||
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
|
||||
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
|
||||
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 }));
|
||||
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: {
|
||||
// Unknown user action
|
||||
console.log('Unknown action from user ' + user.name + ': ' + command.action + '.');
|
||||
|
57
mpsserver.js
57
mpsserver.js
@ -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.setEncoding("binary");
|
||||
Debug(1, "MPS:New CIRA connection");
|
||||
parent.debug('mps', "New CIRA connection");
|
||||
|
||||
// Setup the CIRA keep alive timer
|
||||
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) {
|
||||
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) {
|
||||
case APFProtocol.KEEPALIVE_REQUEST: {
|
||||
if (len < 5) return 0;
|
||||
Debug(3, 'MPS:KEEPALIVE_REQUEST');
|
||||
parent.debug('mpscmd', 'KEEPALIVE_REQUEST');
|
||||
SendKeepAliveReply(socket, common.ReadInt(data, 1));
|
||||
return 5;
|
||||
}
|
||||
case APFProtocol.KEEPALIVE_REPLY: {
|
||||
if (len < 5) return 0;
|
||||
Debug(3, 'MPS:KEEPALIVE_REPLY');
|
||||
parent.debug('mpscmd', 'KEEPALIVE_REPLY');
|
||||
return 5;
|
||||
}
|
||||
case APFProtocol.PROTOCOLVERSION: {
|
||||
@ -314,7 +314,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||
socket.tag.MajorVersion = common.ReadInt(data, 1);
|
||||
socket.tag.MinorVersion = common.ReadInt(data, 5);
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
//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
|
||||
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.
|
||||
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;
|
||||
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 (mesh.mtype == 1) {
|
||||
@ -446,7 +446,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||
var xserviceNameLen = common.ReadInt(data, 1);
|
||||
if (len < 5 + xserviceNameLen) return 0;
|
||||
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 == "auth@amt.intel.com") { SendServiceAccept(socket, "auth@amt.intel.com"); }
|
||||
return 5 + xserviceNameLen;
|
||||
@ -463,7 +463,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||
if (len < 14 + requestLen + addrLen) return 0;
|
||||
var addr = data.substring(10 + requestLen, 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);
|
||||
if (socket.tag.boundPorts.indexOf(port) == -1) { socket.tag.boundPorts.push(port); }
|
||||
SendTcpForwardSuccessReply(socket, port);
|
||||
@ -475,7 +475,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||
if (len < 14 + requestLen + addrLen) return 0;
|
||||
var addr = data.substring(10 + requestLen, 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);
|
||||
if (portindex >= 0) { socket.tag.boundPorts.splice(portindex, 1); }
|
||||
SendTcpForwardCancelReply(socket);
|
||||
@ -493,7 +493,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||
var oport = common.ReadInt(data, 18 + requestLen + addrLen + oaddrLen);
|
||||
var datalen = common.ReadInt(data, 22 + requestLen + addrLen + oaddrLen);
|
||||
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
|
||||
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);
|
||||
|
||||
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
|
||||
//if (ChannelType.toLowerCase() == "direct-tcpip")
|
||||
@ -554,7 +554,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||
cirachannel.amtchannelid = SenderChannel;
|
||||
cirachannel.sendcredits = cirachannel.amtCiraWindow = WindowSize;
|
||||
channelOpenConfirmCount++;
|
||||
Debug(3, 'MPS:CHANNEL_OPEN_CONFIRMATION', RecipientChannel, SenderChannel, WindowSize);
|
||||
parent.debug('mpscmd', 'CHANNEL_OPEN_CONFIRMATION', RecipientChannel, SenderChannel, WindowSize);
|
||||
if (cirachannel.closing == 1) {
|
||||
// Close this channel
|
||||
SendChannelClose(cirachannel.socket, cirachannel.amtchannelid);
|
||||
@ -586,7 +586,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||
var RecipientChannel = common.ReadInt(data, 1);
|
||||
var ReasonCode = common.ReadInt(data, 5);
|
||||
channelOpenFailCount++;
|
||||
Debug(3, 'MPS:CHANNEL_OPEN_FAILURE', RecipientChannel, ReasonCode);
|
||||
parent.debug('mpscmd', 'CHANNEL_OPEN_FAILURE', RecipientChannel, ReasonCode);
|
||||
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.state > 0) {
|
||||
@ -601,7 +601,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||
if (len < 5) return 0;
|
||||
var RecipientChannel = common.ReadInt(data, 1);
|
||||
channelCloseCount++;
|
||||
Debug(3, 'MPS:CHANNEL_CLOSE', RecipientChannel);
|
||||
parent.debug('mpscmd', 'CHANNEL_CLOSE', RecipientChannel);
|
||||
var cirachannel = socket.tag.channels[RecipientChannel];
|
||||
if (cirachannel == null) { console.log("MPS Error in CHANNEL_CLOSE: Unable to find channelid " + RecipientChannel); return 5; }
|
||||
socket.tag.activetunnels--;
|
||||
@ -620,7 +620,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||
var cirachannel = socket.tag.channels[RecipientChannel];
|
||||
if (cirachannel == null) { console.log("MPS Error in CHANNEL_WINDOW_ADJUST: Unable to find channelid " + RecipientChannel); return 9; }
|
||||
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) {
|
||||
// Compute how much data we can send
|
||||
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 LengthOfData = common.ReadInt(data, 5);
|
||||
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];
|
||||
if (cirachannel == null) { console.log("MPS Error in CHANNEL_DATA: Unable to find channelid " + RecipientChannel); return 9 + LengthOfData; }
|
||||
cirachannel.amtpendingcredits += LengthOfData;
|
||||
@ -660,14 +660,14 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||
if (len < 7) return 0;
|
||||
var ReasonCode = common.ReadInt(data, 1);
|
||||
disconnectCommandCount++;
|
||||
Debug(3, 'MPS:DISCONNECT', ReasonCode);
|
||||
parent.debug('mpscmd', 'DISCONNECT', ReasonCode);
|
||||
try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
|
||||
obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
|
||||
return 7;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Debug(1, 'MPS:Unknown CIRA command: ' + cmd);
|
||||
parent.debug('mpscmd', 'Unknown CIRA command: ' + cmd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -675,7 +675,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||
|
||||
socket.addListener("close", function () {
|
||||
socketClosedCount++;
|
||||
Debug(1, 'MPS:CIRA connection closed');
|
||||
parent.debug('mps', 'CIRA connection closed');
|
||||
try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
|
||||
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) {
|
||||
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));
|
||||
}
|
||||
|
||||
@ -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); }
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
@ -61,15 +61,15 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
|
||||
// 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.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
|
||||
obj.ws.on('error', function (error) { obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Error: ' + error); disconnect(); });
|
||||
obj.ws.on('close', function () { obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Disconnected'); 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('peer', 'OutPeer ' + obj.serverid + ': Disconnected'); disconnect(); });
|
||||
|
||||
// Register the connection event
|
||||
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.nonce = obj.crypto.randomBytes(48).toString('binary');
|
||||
|
||||
@ -95,10 +95,10 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
switch (cmd) {
|
||||
case 1: {
|
||||
// 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
|
||||
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);
|
||||
|
||||
// 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 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) { }
|
||||
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, '$');
|
||||
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?)
|
||||
const verify = obj.parent.crypto.createVerify('SHA384');
|
||||
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
|
||||
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.connectionState |= 4;
|
||||
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
|
||||
if (obj.connectionState == 15) {
|
||||
@ -152,7 +152,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -189,7 +189,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
function processServerData(msg) {
|
||||
var str = msg.toString('utf8'), command = null;
|
||||
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 (obj.authenticated != 3) {
|
||||
// We get the peer's serverid and database identifier.
|
||||
@ -233,7 +233,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
obj.serverCertHash = null;
|
||||
obj.pendingData = [];
|
||||
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
|
||||
obj.send = function (data) {
|
||||
@ -246,8 +246,8 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
|
||||
// Disconnect this server
|
||||
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 == 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 == 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('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; }
|
||||
};
|
||||
|
||||
@ -283,7 +283,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
}
|
||||
else if (cmd == 2) {
|
||||
// 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.
|
||||
|
||||
// Decode the certificate
|
||||
@ -296,12 +296,12 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
if (obj.peernonce == null) {
|
||||
obj.unauthsign = msg.substring(4 + certlen);
|
||||
} 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();
|
||||
}
|
||||
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.
|
||||
completePeerServerConnection();
|
||||
}
|
||||
@ -309,11 +309,11 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
});
|
||||
|
||||
// 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.
|
||||
ws.on('close', function (req) { obj.parent.parent.debug(1, '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 + ')'); });
|
||||
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('peer', 'Peer server TCP disconnect ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); });
|
||||
|
||||
// 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
|
||||
@ -355,7 +355,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
function processServerData(msg) {
|
||||
var str = msg.toString('utf8'), command = null;
|
||||
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 (obj.authenticated != 3) {
|
||||
// We get the peer's serverid and database identifier.
|
||||
@ -599,21 +599,21 @@ module.exports.CreateMultiServer = function (parent, args) {
|
||||
|
||||
peerTunnel.connect = function () {
|
||||
// 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 });
|
||||
|
||||
// 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.
|
||||
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?)
|
||||
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
|
||||
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
|
||||
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(); });
|
||||
|
||||
// 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
|
||||
peerTunnel.close = function (arg) {
|
||||
if (arg == 2) {
|
||||
// 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.ws2 != null) { try { peerTunnel.ws2._socket._parent.end(); peerTunnel.parent.parent.debug(1, 'FTunnel2: 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('peer', 'FTunnel2: Hard disconnect'); } catch (e) { console.log(e); } }
|
||||
} else {
|
||||
// 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.ws2 != null) { try { peerTunnel.ws2.close(); peerTunnel.parent.parent.debug(1, 'FTunnel2: 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('peer', 'FTunnel2: Soft disconnect '); } catch (e) { console.log(e); } }
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "meshcentral",
|
||||
"version": "0.4.0-a",
|
||||
"version": "0.4.0-c",
|
||||
"keywords": [
|
||||
"Remote Management",
|
||||
"Intel AMT",
|
||||
|
@ -838,7 +838,7 @@ NoMeshesPanel img {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
#p3events, #p16events, #p31events {
|
||||
#p3events, #p16events, #p31events, #p41events {
|
||||
height: calc(100vh - 245px);
|
||||
overflow-y: scroll;
|
||||
}
|
||||
@ -2539,4 +2539,14 @@ a {
|
||||
border-radius:4px;
|
||||
padding:6px;
|
||||
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;
|
||||
}
|
@ -10,6 +10,7 @@
|
||||
"_Minify": 1,
|
||||
"_SessionTime": 30,
|
||||
"_SessionKey": "MyReallySecretPassword1",
|
||||
"_SessionSameSite": "strict",
|
||||
"_DbEncryptKey": "MyReallySecretPassword2",
|
||||
"_DbExpire": {
|
||||
"events": 1728000,
|
||||
@ -20,6 +21,7 @@
|
||||
"_AllowLoginToken": true,
|
||||
"_AllowFraming": true,
|
||||
"_WebRTC": false,
|
||||
"_Nice404": false,
|
||||
"_ClickOnce": false,
|
||||
"_SelfUpdate": true,
|
||||
"_AgentPing": 60,
|
||||
|
@ -202,11 +202,11 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
||||
|
||||
switch (cmd) {
|
||||
case LegacyMeshProtocol.NODEPUSH: {
|
||||
Debug(3, 'Swarm:NODEPUSH');
|
||||
parent.debug('swarmcmd', 'NODEPUSH');
|
||||
var nodeblock = obj.decodeNodeBlock(data);
|
||||
if ((nodeblock != null) && (nodeblock.agenttype != null) && (nodeblock.agentversion != null)) {
|
||||
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
|
||||
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;
|
||||
}
|
||||
case LegacyMeshProtocol.AMTPROVISIONING: {
|
||||
Debug(3, 'Swarm:AMTPROVISIONING');
|
||||
parent.debug('swarmcmd', 'AMTPROVISIONING');
|
||||
obj.SendCommand(socket, LegacyMeshProtocol.AMTPROVISIONING, common.ShortToStr(1));
|
||||
break;
|
||||
}
|
||||
case LegacyMeshProtocol.GETSTATE: {
|
||||
Debug(3, 'Swarm:GETSTATE');
|
||||
parent.debug('swarmcmd', 'GETSTATE');
|
||||
if (len < 12) break;
|
||||
var statecmd = common.ReadInt(data, 0);
|
||||
//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); }
|
||||
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);
|
||||
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;
|
||||
if (socket.tag.updatePtr >= socket.tag.update.binary.length) {
|
||||
// Send end-of-transfer
|
||||
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
|
||||
delete socket.tag.taskid;
|
||||
delete socket.tag.update;
|
||||
@ -295,11 +295,11 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
||||
break;
|
||||
}
|
||||
case LegacyMeshProtocol.APPSUBSCRIBERS: {
|
||||
Debug(3, 'Swarm:APPSUBSCRIBERS');
|
||||
parent.debug('swarmcmd', 'APPSUBSCRIBERS');
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
Debug(1, 'Swarm:Unknown command: ' + cmd + ' of len ' + len + '.');
|
||||
parent.debug('swarmcmd', 'Unknown command: ' + cmd + ' of len ' + len + '.');
|
||||
}
|
||||
}
|
||||
return len;
|
||||
@ -308,18 +308,18 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
|
||||
// Called when a legacy agent connects to this server
|
||||
function onConnection(socket) {
|
||||
// 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++;
|
||||
|
||||
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++; }
|
||||
|
||||
socket.addListener("data", onData);
|
||||
socket.addListener("close", function () {
|
||||
obj.stats.onclose++;
|
||||
Debug(1, 'Swarm:Connection closed');
|
||||
parent.debug('swarm', 'Connection closed');
|
||||
|
||||
// Perform aggressive cleanup
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
File diff suppressed because one or more lines are too long
@ -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=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=ServerTrace class="topbar_td style3x" onclick=go(41) onkeypress="if (event.key == 'Enter') go(41)">Trace</td>
|
||||
<td class="topbar_td_end style3"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -783,7 +784,7 @@
|
||||
</table>
|
||||
<div id=p31events style=""></div>
|
||||
</div>
|
||||
<div id=p40 style="display:none;">
|
||||
<div id=p40 style="display:none">
|
||||
<h1>My Server Stats</h1>
|
||||
<div class="areaHead">
|
||||
<div class="toright2">
|
||||
@ -807,6 +808,27 @@
|
||||
</div>
|
||||
<canvas id=serverMainStats style=""></canvas>
|
||||
</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()>
|
||||
</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" />
|
||||
</div>
|
||||
<div id="footer">
|
||||
@ -1283,6 +1305,7 @@
|
||||
}
|
||||
meshserver.send({ action: 'events', limit: parseInt(p3limitdropdown.value) });
|
||||
QV('ServerConsole', userinfo.siteadmin === 0xFFFFFFFF);
|
||||
QV('ServerTrace', userinfo.siteadmin === 0xFFFFFFFF);
|
||||
if ((xxcurrentView == 115) && (userinfo.siteadmin != 0xFFFFFFFF)) { go(6); }
|
||||
if ((xxcurrentView == 6) && ((userinfo.siteadmin & 21) == 0)) { go(1); }
|
||||
|
||||
@ -1361,6 +1384,22 @@
|
||||
|
||||
function onMessage(server, message) {
|
||||
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': {
|
||||
updateGeneralServerStats(message);
|
||||
break;
|
||||
@ -2078,6 +2117,17 @@
|
||||
addNotification(n);
|
||||
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.
|
||||
// Disconnect
|
||||
//console.log(message.msg);
|
||||
@ -8545,6 +8595,57 @@
|
||||
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
|
||||
//
|
||||
@ -8608,7 +8709,7 @@
|
||||
QV('uiMenu', false);
|
||||
|
||||
// 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;
|
||||
|
||||
// Remove top bar selection
|
||||
@ -8666,8 +8767,8 @@
|
||||
QV('UserDummyMenuSpan', (x < 10) && (x != 6) && webPageFullScreen);
|
||||
QV('MeshSubMenuSpan', x >= 20 && x < 30);
|
||||
QV('UserSubMenuSpan', x >= 30 && x < 40);
|
||||
QV('ServerSubMenuSpan', x == 6 || x == 115 || x == 40);
|
||||
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' };
|
||||
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', 41: 'ServerTrace', 115: 'ServerConsole' };
|
||||
for (var i in panels) {
|
||||
QC(panels[i]).remove('style3x');
|
||||
QC(panels[i]).remove('style3sel');
|
||||
|
File diff suppressed because one or more lines are too long
96
webserver.js
96
webserver.js
@ -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.
|
||||
function isTrustedCert() {
|
||||
function isTrustedCert(domain) {
|
||||
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.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.CommonName.indexOf('.') == -1) return false; // Our cert is named with a fake name
|
||||
return true; // This is a guess
|
||||
@ -1920,8 +1922,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
// Handle a web socket relay request
|
||||
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
|
||||
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
|
||||
|
||||
// Fetch information about the target
|
||||
@ -1937,7 +1939,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
// Check what connectivity is available for this node
|
||||
var state = parent.GetConnectivityState(req.query.host);
|
||||
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
|
||||
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.serverid != obj.parent.serverId) {
|
||||
// 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);
|
||||
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
|
||||
if ((server != null) && (server.serverid != obj.parent.serverId)) {
|
||||
// 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);
|
||||
return;
|
||||
}
|
||||
@ -1984,7 +1986,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
|
||||
// If Intel AMT CIRA connection is available, use it
|
||||
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];
|
||||
|
||||
@ -2010,13 +2012,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
// When APF tunnel return something, update SerialTunnel buffer
|
||||
chnl.onData = function (ciraconn, data) {
|
||||
// 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) { } }
|
||||
};
|
||||
|
||||
// Handle CIRA tunnel state change
|
||||
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) { } }
|
||||
};
|
||||
|
||||
@ -2024,8 +2026,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
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 tlsock = new TLSSocket(ser, tlsoptions);
|
||||
tlsock.on('error', function (err) { Debug(1, "CIRA TLS Connection Error ", err); });
|
||||
tlsock.on('secureConnect', function () { Debug(2, "CIRA Secure TLS Connection"); ws._socket.resume(); });
|
||||
tlsock.on('error', function (err) { parent.debug('webrelay', "CIRA TLS Connection Error ", err); });
|
||||
tlsock.on('secureConnect', function () { parent.debug('webrelay', "CIRA Secure TLS Connection"); ws._socket.resume(); });
|
||||
|
||||
// Decrypted tunnel from TLS communcation to be forwarded to websocket
|
||||
tlsock.on('data', function (data) {
|
||||
@ -2070,7 +2072,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
// If error, close the associated TCP connection.
|
||||
ws.on('error', function (err) {
|
||||
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
|
||||
|
||||
// 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.
|
||||
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
|
||||
|
||||
// Close the recording file
|
||||
@ -2097,12 +2099,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
});
|
||||
|
||||
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) { } }
|
||||
};
|
||||
|
||||
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
|
||||
//console.log('AMT --> WS', Buffer.from(data, 'binary').toString('hex'));
|
||||
if (data.length > 0) {
|
||||
@ -2123,12 +2125,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
|
||||
// Fetch Intel AMT credentials & Setup interceptor
|
||||
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.blockAmtStorage = true;
|
||||
}
|
||||
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.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 ((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.
|
||||
ws.on('message', function (msg) {
|
||||
if (obj.parent.debugLevel >= 1) { // DEBUG
|
||||
Debug(2, 'TCP relay data to ' + node.host + ', ' + msg.length + ' bytes');
|
||||
if (obj.parent.debugLevel >= 4) { Debug(4, ' ' + msg.toString('hex')); }
|
||||
parent.debug('webrelaydata', 'TCP relay data to ' + node.host + ', ' + msg.length + ' bytes');
|
||||
//if (obj.parent.debugLevel >= 4) { parent.debug('webrelaydatahex', ' ' + msg.toString('hex')); }
|
||||
}
|
||||
msg = msg.toString('binary');
|
||||
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.
|
||||
ws.on('error', function (err) {
|
||||
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) { } }
|
||||
|
||||
// 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.
|
||||
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) { } }
|
||||
|
||||
// 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 };
|
||||
ws.forwardclient = obj.tls.connect(port, node.host, tlsoptions, function () {
|
||||
// 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._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.
|
||||
ws.forwardclient.on('data', function (data) {
|
||||
if (obj.parent.debugLevel >= 1) { // DEBUG
|
||||
Debug(2, 'TCP relay data from ' + node.host + ', ' + data.length + ' bytes.');
|
||||
if (obj.parent.debugLevel >= 4) { Debug(4, ' ' + Buffer.from(data, 'binary').toString('hex')); }
|
||||
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 (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor
|
||||
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.
|
||||
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) { }
|
||||
});
|
||||
|
||||
// If the TCP connection causes an error, disconnect the associated web socket.
|
||||
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) { }
|
||||
});
|
||||
|
||||
@ -2251,7 +2253,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
if (node.intelamt.tls == 0) {
|
||||
// A TCP connection to Intel AMT just connected, start forwarding.
|
||||
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._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 + '"' });
|
||||
var data = scriptInfo.data;
|
||||
var cmdoptions = { wgetoptionshttp: '', wgetoptionshttps: '', curloptionshttp: '-L ', curloptionshttps: '-L ' }
|
||||
if (isTrustedCert() != true) {
|
||||
if (isTrustedCert(domain) != true) {
|
||||
cmdoptions.wgetoptionshttps += '--no-check-certificate ';
|
||||
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
|
||||
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); }
|
||||
obj.app.use(obj.session(sessionOptions));
|
||||
|
||||
// Add HTTP security headers to all responses
|
||||
obj.app.use(function (req, res, next) {
|
||||
parent.debug('webrequest', req.url);
|
||||
res.removeHeader("X-Powered-By");
|
||||
var domain = req.xdomain = getDomain(req);
|
||||
|
||||
@ -3086,7 +3090,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
// Receive mesh agent connections
|
||||
obj.app.ws(url + 'agent.ashx', function (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);
|
||||
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));
|
||||
|
||||
// Handle 404 error
|
||||
obj.app.use(function (req, res, next) {
|
||||
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 });
|
||||
})
|
||||
if (obj.args.nice404 !== false) {
|
||||
obj.app.use(function (req, res, next) {
|
||||
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.
|
||||
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()]);
|
||||
} else {
|
||||
// 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) { }
|
||||
}
|
||||
}
|
||||
@ -3198,7 +3205,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
func(ws, req, domain, obj.users[cookie.userid], cookie);
|
||||
} else {
|
||||
// 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) { }
|
||||
}
|
||||
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()]);
|
||||
} else {
|
||||
// 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) { }
|
||||
}
|
||||
}
|
||||
@ -3257,7 +3264,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
|
||||
if (noAuthOk != true) {
|
||||
// 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) { }
|
||||
} else {
|
||||
// Continue this session without user authentication,
|
||||
@ -3359,17 +3366,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
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.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd)
|
||||
|
Loading…
Reference in New Issue
Block a user