mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-01-08 23:21:11 +03:00
Much improved Windows MeshAgent stability
This commit is contained in:
parent
c53d51175a
commit
f6ef228de6
@ -28,6 +28,8 @@
|
|||||||
<Compile Include="amtevents.js" />
|
<Compile Include="amtevents.js" />
|
||||||
<Compile Include="amtscanner.js" />
|
<Compile Include="amtscanner.js" />
|
||||||
<Compile Include="amtscript.js" />
|
<Compile Include="amtscript.js" />
|
||||||
|
<Compile Include="letsEncrypt.js" />
|
||||||
|
<Compile Include="meshaccelerator.js" />
|
||||||
<Compile Include="meshmail.js" />
|
<Compile Include="meshmail.js" />
|
||||||
<Compile Include="meshscanner.js" />
|
<Compile Include="meshscanner.js" />
|
||||||
<Compile Include="certoperations.js" />
|
<Compile Include="certoperations.js" />
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -472,7 +472,6 @@ function createMeshCore(agent) {
|
|||||||
|
|
||||||
function onTunnelClosed() {
|
function onTunnelClosed() {
|
||||||
sendConsoleText("Tunnel #" + this.httprequest.index + " closed.", this.httprequest.sessionid);
|
sendConsoleText("Tunnel #" + this.httprequest.index + " closed.", this.httprequest.sessionid);
|
||||||
if (this.httprequest.protocol == 1) { this.httprequest.process.end(); delete this.httprequest.process; }
|
|
||||||
delete tunnels[this.httprequest.index];
|
delete tunnels[this.httprequest.index];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -561,7 +560,8 @@ function createMeshCore(agent) {
|
|||||||
this.httprequest.process.on('exit', function (ecode, sig) { this.tunnel.end(); });
|
this.httprequest.process.on('exit', function (ecode, sig) { this.tunnel.end(); });
|
||||||
this.httprequest.process.stderr.on('data', function (chunk) { this.parent.tunnel.write(chunk); });
|
this.httprequest.process.stderr.on('data', function (chunk) { this.parent.tunnel.write(chunk); });
|
||||||
this.httprequest.process.stdout.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
this.httprequest.process.stdout.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
||||||
this.pipe(this.httprequest.process.stdin, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
this.pipe(this.httprequest.process.stdin, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||||
|
this.prependListener('end', function () { this.httprequest.process.kill(); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.httprequest.protocol == 2) {
|
if (this.httprequest.protocol == 2) {
|
||||||
@ -717,7 +717,15 @@ function createMeshCore(agent) {
|
|||||||
var response = null;
|
var response = null;
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case 'help': { // Displays available commands
|
case 'help': { // Displays available commands
|
||||||
response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseuri, httpget, wslist,\r\nwsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power, wakeonlan, scanwifi, scanamt.';
|
response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, eval, parseuri, httpget,\r\nwslist, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power, wakeonlan, scanwifi, scanamt.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'eval': { // Eval JavaScript
|
||||||
|
if (args['_'].length < 1) {
|
||||||
|
response = 'Proper usage: eval "JavaScript code"'; // Display correct command usage
|
||||||
|
} else {
|
||||||
|
response = JSON.stringify(mesh.eval(args['_'][0]));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'notify': { // Send a notification message to the mesh
|
case 'notify': { // Send a notification message to the mesh
|
||||||
@ -735,6 +743,7 @@ function createMeshCore(agent) {
|
|||||||
response = 'Current Core: ' + obj.meshCoreInfo + '.\r\nAgent Time: ' + Date() + '.\r\nUser Rights: 0x' + rights.toString(16) + '.\r\nPlatform Info: ' + process.platform + '.\r\nCapabilities: ' + obj.meshCoreCapabilities + '.\r\nNative Pipes: ' + obj.useNativePipes + '.\r\nServer URL: ' + mesh.ServerUrl + '.';
|
response = 'Current Core: ' + obj.meshCoreInfo + '.\r\nAgent Time: ' + Date() + '.\r\nUser Rights: 0x' + rights.toString(16) + '.\r\nPlatform Info: ' + process.platform + '.\r\nCapabilities: ' + obj.meshCoreCapabilities + '.\r\nNative Pipes: ' + obj.useNativePipes + '.\r\nServer URL: ' + mesh.ServerUrl + '.';
|
||||||
if (amtLmsState >= 0) { response += '\r\nBuilt -in LMS: ' + ['Disabled', 'Connecting..', 'Connected'][amtLmsState] + '.'; }
|
if (amtLmsState >= 0) { response += '\r\nBuilt -in LMS: ' + ['Disabled', 'Connecting..', 'Connected'][amtLmsState] + '.'; }
|
||||||
response += '\r\nModules: ' + JSON.stringify(addedModules) + '';
|
response += '\r\nModules: ' + JSON.stringify(addedModules) + '';
|
||||||
|
response += '\r\nServerConnected: ' + mesh.isControlChannelConnected + '';
|
||||||
var oldNodeId = db.Get('OldNodeId');
|
var oldNodeId = db.Get('OldNodeId');
|
||||||
if (oldNodeId != null) { response += '\r\nOldNodeID: ' + oldNodeId + '.'; }
|
if (oldNodeId != null) { response += '\r\nOldNodeID: ' + oldNodeId + '.'; }
|
||||||
response += '\r\ServerState: ' + meshServerConnectionState + '.';
|
response += '\r\ServerState: ' + meshServerConnectionState + '.';
|
||||||
@ -1136,16 +1145,11 @@ function createMeshCore(agent) {
|
|||||||
// Setup the mesh agent event handlers
|
// Setup the mesh agent event handlers
|
||||||
mesh.AddCommandHandler(handleServerCommand);
|
mesh.AddCommandHandler(handleServerCommand);
|
||||||
mesh.AddConnectHandler(handleServerConnection);
|
mesh.AddConnectHandler(handleServerConnection);
|
||||||
//mesh.lmsNotification = handleAmtNotification; // TODO
|
|
||||||
sendPeriodicServerUpdate(true); // TODO: Check if connected before sending
|
|
||||||
|
|
||||||
// Parse input arguments
|
// Parse input arguments
|
||||||
//var args = parseArgs(process.argv);
|
//var args = parseArgs(process.argv);
|
||||||
//console.log(args);
|
//console.log(args);
|
||||||
|
|
||||||
//console.log('Stopping.');
|
|
||||||
//process.exit();
|
|
||||||
|
|
||||||
// Launch LMS
|
// Launch LMS
|
||||||
try {
|
try {
|
||||||
var lme_heci = require('lme_heci');
|
var lme_heci = require('lme_heci');
|
||||||
@ -1154,6 +1158,14 @@ function createMeshCore(agent) {
|
|||||||
amtLms.on('error', function (e) { amtLmsState = 0; amtLms = null; });
|
amtLms.on('error', function (e) { amtLmsState = 0; amtLms = null; });
|
||||||
amtLms.on('connect', function () { amtLmsState = 2; });
|
amtLms.on('connect', function () { amtLmsState = 2; });
|
||||||
} catch (e) { amtLmsState = -1; amtLms = null; }
|
} catch (e) { amtLmsState = -1; amtLms = null; }
|
||||||
|
|
||||||
|
// Check if the control channel is connected
|
||||||
|
if (mesh.isControlChannelConnected) {
|
||||||
|
sendPeriodicServerUpdate(true); // Send the server update
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log('Stopping.');
|
||||||
|
//process.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.stop = function () {
|
obj.stop = function () {
|
||||||
|
@ -79,7 +79,7 @@ function AMTScanner() {
|
|||||||
server.bind({ address: '0.0.0.0', port: 0, exclusive: true });
|
server.bind({ address: '0.0.0.0', port: 0, exclusive: true });
|
||||||
var tmout = setTimeout(function cb() {
|
var tmout = setTimeout(function cb() {
|
||||||
//console.log("Server closed");
|
//console.log("Server closed");
|
||||||
//server.close();
|
server.close();
|
||||||
server.parent.emit('found', server.scanResults);
|
server.parent.emit('found', server.scanResults);
|
||||||
delete server;
|
delete server;
|
||||||
}, timeout);
|
}, timeout);
|
||||||
|
@ -21,8 +21,7 @@ var APF_CHANNEL_CLOSE = 97;
|
|||||||
var APF_PROTOCOLVERSION = 192;
|
var APF_PROTOCOLVERSION = 192;
|
||||||
|
|
||||||
|
|
||||||
function lme_object()
|
function lme_object() {
|
||||||
{
|
|
||||||
this.ourId = ++lme_id;
|
this.ourId = ++lme_id;
|
||||||
this.amtId = -1;
|
this.amtId = -1;
|
||||||
this.LME_CHANNEL_STATUS = 'LME_CS_FREE';
|
this.LME_CHANNEL_STATUS = 'LME_CS_FREE';
|
||||||
@ -32,8 +31,7 @@ function lme_object()
|
|||||||
this.errorCount = 0;
|
this.errorCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function stream_bufferedWrite()
|
function stream_bufferedWrite() {
|
||||||
{
|
|
||||||
var emitterUtils = require('events').inherits(this);
|
var emitterUtils = require('events').inherits(this);
|
||||||
this.buffer = [];
|
this.buffer = [];
|
||||||
this._readCheckImmediate = undefined;
|
this._readCheckImmediate = undefined;
|
||||||
@ -48,18 +46,14 @@ function stream_bufferedWrite()
|
|||||||
|
|
||||||
// Readable Events
|
// Readable Events
|
||||||
emitterUtils.createEvent('readable');
|
emitterUtils.createEvent('readable');
|
||||||
this.isEmpty = function ()
|
this.isEmpty = function () {
|
||||||
{
|
|
||||||
return (this.buffer.length == 0);
|
return (this.buffer.length == 0);
|
||||||
};
|
};
|
||||||
this.isWaiting = function ()
|
this.isWaiting = function () {
|
||||||
{
|
|
||||||
return (this._readCheckImmediate == undefined);
|
return (this._readCheckImmediate == undefined);
|
||||||
};
|
};
|
||||||
this.write = function (chunk)
|
this.write = function (chunk) {
|
||||||
{
|
for (var args in arguments) {
|
||||||
for (var args in arguments)
|
|
||||||
{
|
|
||||||
if (typeof (arguments[args]) == 'function') { this.once('drain', arguments[args]); break; }
|
if (typeof (arguments[args]) == 'function') { this.once('drain', arguments[args]); break; }
|
||||||
}
|
}
|
||||||
var tmp = Buffer.alloc(chunk.length);
|
var tmp = Buffer.alloc(chunk.length);
|
||||||
@ -68,41 +62,34 @@ function stream_bufferedWrite()
|
|||||||
this.emit('readable');
|
this.emit('readable');
|
||||||
return (this.buffer.length == 0 ? true : false);
|
return (this.buffer.length == 0 ? true : false);
|
||||||
};
|
};
|
||||||
this.read = function ()
|
this.read = function () {
|
||||||
{
|
|
||||||
var size = arguments.length == 0 ? undefined : arguments[0];
|
var size = arguments.length == 0 ? undefined : arguments[0];
|
||||||
var bytesRead = 0;
|
var bytesRead = 0;
|
||||||
var list = [];
|
var list = [];
|
||||||
while((size == undefined || bytesRead < size) && this.buffer.length > 0)
|
while ((size == undefined || bytesRead < size) && this.buffer.length > 0) {
|
||||||
{
|
|
||||||
var len = this.buffer[0].data.length - this.buffer[0].offset;
|
var len = this.buffer[0].data.length - this.buffer[0].offset;
|
||||||
var offset = this.buffer[0].offset;
|
var offset = this.buffer[0].offset;
|
||||||
|
|
||||||
if(len > (size - bytesRead))
|
if (len > (size - bytesRead)) {
|
||||||
{
|
|
||||||
// Only reading a subset
|
// Only reading a subset
|
||||||
list.push(this.buffer[0].data.slice(offset, offset + size - bytesRead));
|
list.push(this.buffer[0].data.slice(offset, offset + size - bytesRead));
|
||||||
this.buffer[0].offset += (size - bytesRead);
|
this.buffer[0].offset += (size - bytesRead);
|
||||||
bytesRead += (size - bytesRead);
|
bytesRead += (size - bytesRead);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
// Reading the entire thing
|
// Reading the entire thing
|
||||||
list.push(this.buffer[0].data.slice(offset));
|
list.push(this.buffer[0].data.slice(offset));
|
||||||
bytesRead += len;
|
bytesRead += len;
|
||||||
this.buffer.shift();
|
this.buffer.shift();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._readCheckImmediate = setImmediate(function (buffered)
|
this._readCheckImmediate = setImmediate(function (buffered) {
|
||||||
{
|
|
||||||
buffered._readCheckImmediate = undefined;
|
buffered._readCheckImmediate = undefined;
|
||||||
if(buffered.buffer.length == 0)
|
if (buffered.buffer.length == 0) {
|
||||||
{
|
|
||||||
// drained
|
// drained
|
||||||
buffered.emit('drain');
|
buffered.emit('drain');
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
// not drained
|
// not drained
|
||||||
buffered.emit('readable');
|
buffered.emit('readable');
|
||||||
}
|
}
|
||||||
@ -112,8 +99,7 @@ function stream_bufferedWrite()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function lme_heci()
|
function lme_heci() {
|
||||||
{
|
|
||||||
var emitterUtils = require('events').inherits(this);
|
var emitterUtils = require('events').inherits(this);
|
||||||
emitterUtils.createEvent('error');
|
emitterUtils.createEvent('error');
|
||||||
emitterUtils.createEvent('connect');
|
emitterUtils.createEvent('connect');
|
||||||
@ -123,17 +109,14 @@ function lme_heci()
|
|||||||
|
|
||||||
this._LME = heci.create();
|
this._LME = heci.create();
|
||||||
this._LME.LMS = this;
|
this._LME.LMS = this;
|
||||||
this._LME.on('error', function (e) { this.Parent.emit('error', e); });
|
this._LME.on('error', function (e) { this.LMS.emit('error', e); });
|
||||||
this._LME.on('connect', function ()
|
this._LME.on('connect', function () {
|
||||||
{
|
|
||||||
this.LMS.emit('connect');
|
this.LMS.emit('connect');
|
||||||
this.on('data', function (chunk)
|
this.on('data', function (chunk) {
|
||||||
{
|
|
||||||
// this = HECI
|
// this = HECI
|
||||||
var cmd = chunk.readUInt8(0);
|
var cmd = chunk.readUInt8(0);
|
||||||
|
|
||||||
switch(cmd)
|
switch (cmd) {
|
||||||
{
|
|
||||||
default:
|
default:
|
||||||
//console.log('Received ' + chunk.length + ' bytes of data for LMS');
|
//console.log('Received ' + chunk.length + ' bytes of data for LMS');
|
||||||
//console.log('Command = ' + cmd);
|
//console.log('Command = ' + cmd);
|
||||||
@ -142,8 +125,7 @@ function lme_heci()
|
|||||||
var nameLen = chunk.readUInt32BE(1);
|
var nameLen = chunk.readUInt32BE(1);
|
||||||
var name = chunk.slice(5, nameLen + 5);
|
var name = chunk.slice(5, nameLen + 5);
|
||||||
//console.log("Service Request for: " + name);
|
//console.log("Service Request for: " + name);
|
||||||
if (name == 'pfwd@amt.intel.com' || name == 'auth@amt.intel.com')
|
if (name == 'pfwd@amt.intel.com' || name == 'auth@amt.intel.com') {
|
||||||
{
|
|
||||||
var outBuffer = Buffer.alloc(5 + nameLen);
|
var outBuffer = Buffer.alloc(5 + nameLen);
|
||||||
outBuffer.writeUInt8(6, 0);
|
outBuffer.writeUInt8(6, 0);
|
||||||
outBuffer.writeUInt32BE(nameLen, 1);
|
outBuffer.writeUInt32BE(nameLen, 1);
|
||||||
@ -151,8 +133,7 @@ function lme_heci()
|
|||||||
this.write(outBuffer);
|
this.write(outBuffer);
|
||||||
//console.log('Answering APF_SERVICE_REQUEST');
|
//console.log('Answering APF_SERVICE_REQUEST');
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
//console.log('UNKNOWN APF_SERVICE_REQUEST');
|
//console.log('UNKNOWN APF_SERVICE_REQUEST');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -160,21 +141,18 @@ function lme_heci()
|
|||||||
var nameLen = chunk.readUInt32BE(1);
|
var nameLen = chunk.readUInt32BE(1);
|
||||||
var name = chunk.slice(5, nameLen + 5).toString();
|
var name = chunk.slice(5, nameLen + 5).toString();
|
||||||
|
|
||||||
switch(name)
|
switch (name) {
|
||||||
{
|
|
||||||
case 'tcpip-forward':
|
case 'tcpip-forward':
|
||||||
var len = chunk.readUInt32BE(nameLen + 6);
|
var len = chunk.readUInt32BE(nameLen + 6);
|
||||||
var port = chunk.readUInt32BE(nameLen + 10 + len);
|
var port = chunk.readUInt32BE(nameLen + 10 + len);
|
||||||
//console.log("[" + chunk.length + "/" + len + "] APF_GLOBAL_REQUEST for: " + name + " on port " + port);
|
//console.log("[" + chunk.length + "/" + len + "] APF_GLOBAL_REQUEST for: " + name + " on port " + port);
|
||||||
if (this[name] == undefined)
|
if (this[name] == undefined) {
|
||||||
{
|
|
||||||
this[name] = {};
|
this[name] = {};
|
||||||
}
|
}
|
||||||
this[name][port] = require('net').createServer();
|
this[name][port] = require('net').createServer();
|
||||||
this[name][port].HECI = this;
|
this[name][port].HECI = this;
|
||||||
this[name][port].listen({ port: port });
|
this[name][port].listen({ port: port });
|
||||||
this[name][port].on('connection', function (socket)
|
this[name][port].on('connection', function (socket) {
|
||||||
{
|
|
||||||
//console.log('New [' + socket.remoteFamily + '] TCP Connection on: ' + socket.remoteAddress + ' :' + socket.localPort);
|
//console.log('New [' + socket.remoteFamily + '] TCP Connection on: ' + socket.remoteAddress + ' :' + socket.localPort);
|
||||||
this.HECI.LMS.bindDuplexStream(socket, socket.remoteFamily, socket.localPort);
|
this.HECI.LMS.bindDuplexStream(socket, socket.remoteFamily, socket.localPort);
|
||||||
});
|
});
|
||||||
@ -197,8 +175,7 @@ function lme_heci()
|
|||||||
var sChannel = chunk.readUInt32BE(5);
|
var sChannel = chunk.readUInt32BE(5);
|
||||||
var wSize = chunk.readUInt32BE(9);
|
var wSize = chunk.readUInt32BE(9);
|
||||||
//console.log('rChannel/' + rChannel + ', sChannel/' + sChannel + ', wSize/' + wSize);
|
//console.log('rChannel/' + rChannel + ', sChannel/' + sChannel + ', wSize/' + wSize);
|
||||||
if (this.sockets[rChannel] != undefined)
|
if (this.sockets[rChannel] != undefined) {
|
||||||
{
|
|
||||||
this.sockets[rChannel].lme.amtId = sChannel;
|
this.sockets[rChannel].lme.amtId = sChannel;
|
||||||
this.sockets[rChannel].lme.rxWindow = wSize;
|
this.sockets[rChannel].lme.rxWindow = wSize;
|
||||||
this.sockets[rChannel].lme.txWindow = wSize;
|
this.sockets[rChannel].lme.txWindow = wSize;
|
||||||
@ -206,10 +183,8 @@ function lme_heci()
|
|||||||
//console.log('LME_CS_CONNECTED');
|
//console.log('LME_CS_CONNECTED');
|
||||||
this.sockets[rChannel].bufferedStream = new stream_bufferedWrite();
|
this.sockets[rChannel].bufferedStream = new stream_bufferedWrite();
|
||||||
this.sockets[rChannel].bufferedStream.socket = this.sockets[rChannel];
|
this.sockets[rChannel].bufferedStream.socket = this.sockets[rChannel];
|
||||||
this.sockets[rChannel].bufferedStream.on('readable', function ()
|
this.sockets[rChannel].bufferedStream.on('readable', function () {
|
||||||
{
|
if (this.socket.lme.txWindow > 0) {
|
||||||
if(this.socket.lme.txWindow > 0)
|
|
||||||
{
|
|
||||||
var buffer = this.read(this.socket.lme.txWindow);
|
var buffer = this.read(this.socket.lme.txWindow);
|
||||||
var packet = Buffer.alloc(9 + buffer.length);
|
var packet = Buffer.alloc(9 + buffer.length);
|
||||||
packet.writeUInt8(APF_CHANNEL_DATA, 0);
|
packet.writeUInt8(APF_CHANNEL_DATA, 0);
|
||||||
@ -220,16 +195,13 @@ function lme_heci()
|
|||||||
this.socket.HECI.write(packet);
|
this.socket.HECI.write(packet);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.sockets[rChannel].bufferedStream.on('drain', function ()
|
this.sockets[rChannel].bufferedStream.on('drain', function () {
|
||||||
{
|
|
||||||
this.socket.resume();
|
this.socket.resume();
|
||||||
});
|
});
|
||||||
this.sockets[rChannel].on('data', function (chunk)
|
this.sockets[rChannel].on('data', function (chunk) {
|
||||||
{
|
|
||||||
if (!this.bufferedStream.write(chunk)) { this.pause(); }
|
if (!this.bufferedStream.write(chunk)) { this.pause(); }
|
||||||
});
|
});
|
||||||
this.sockets[rChannel].on('end', function ()
|
this.sockets[rChannel].on('end', function () {
|
||||||
{
|
|
||||||
var outBuffer = Buffer.alloc(5);
|
var outBuffer = Buffer.alloc(5);
|
||||||
outBuffer.writeUInt8(APF_CHANNEL_CLOSE, 0);
|
outBuffer.writeUInt8(APF_CHANNEL_CLOSE, 0);
|
||||||
outBuffer.writeUInt32BE(this.lme.amtId, 1);
|
outBuffer.writeUInt32BE(this.lme.amtId, 1);
|
||||||
@ -254,16 +226,13 @@ function lme_heci()
|
|||||||
case APF_CHANNEL_WINDOW_ADJUST:
|
case APF_CHANNEL_WINDOW_ADJUST:
|
||||||
var rChannelId = chunk.readUInt32BE(1);
|
var rChannelId = chunk.readUInt32BE(1);
|
||||||
var bytesToAdd = chunk.readUInt32BE(5);
|
var bytesToAdd = chunk.readUInt32BE(5);
|
||||||
if (this.sockets[rChannelId] != undefined)
|
if (this.sockets[rChannelId] != undefined) {
|
||||||
{
|
|
||||||
this.sockets[rChannelId].lme.txWindow += bytesToAdd;
|
this.sockets[rChannelId].lme.txWindow += bytesToAdd;
|
||||||
if (!this.sockets[rChannelId].bufferedStream.isEmpty() && this.sockets[rChannelId].bufferedStream.isWaiting())
|
if (!this.sockets[rChannelId].bufferedStream.isEmpty() && this.sockets[rChannelId].bufferedStream.isWaiting()) {
|
||||||
{
|
|
||||||
this.sockets[rChannelId].bufferedStream.emit('readable');
|
this.sockets[rChannelId].bufferedStream.emit('readable');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
//console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_WINDOW_ADJUST');
|
//console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_WINDOW_ADJUST');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -271,11 +240,9 @@ function lme_heci()
|
|||||||
var rChannelId = chunk.readUInt32BE(1);
|
var rChannelId = chunk.readUInt32BE(1);
|
||||||
var dataLen = chunk.readUInt32BE(5);
|
var dataLen = chunk.readUInt32BE(5);
|
||||||
var data = chunk.slice(9, 9 + dataLen);
|
var data = chunk.slice(9, 9 + dataLen);
|
||||||
if (this.sockets[rChannelId] != undefined)
|
if (this.sockets[rChannelId] != undefined) {
|
||||||
{
|
|
||||||
this.sockets[rChannelId].pendingBytes.push(data.length);
|
this.sockets[rChannelId].pendingBytes.push(data.length);
|
||||||
this.sockets[rChannelId].write(data, function ()
|
this.sockets[rChannelId].write(data, function () {
|
||||||
{
|
|
||||||
var written = this.pendingBytes.shift();
|
var written = this.pendingBytes.shift();
|
||||||
var outBuffer = Buffer.alloc(9);
|
var outBuffer = Buffer.alloc(9);
|
||||||
outBuffer.writeUInt8(APF_CHANNEL_WINDOW_ADJUST, 0);
|
outBuffer.writeUInt8(APF_CHANNEL_WINDOW_ADJUST, 0);
|
||||||
@ -284,15 +251,13 @@ function lme_heci()
|
|||||||
this.HECI.write(outBuffer);
|
this.HECI.write(outBuffer);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
//console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_DATA');
|
//console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_DATA');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case APF_CHANNEL_CLOSE:
|
case APF_CHANNEL_CLOSE:
|
||||||
var rChannelId = chunk.readUInt32BE(1);
|
var rChannelId = chunk.readUInt32BE(1);
|
||||||
if (this.sockets[rChannelId] != undefined)
|
if (this.sockets[rChannelId] != undefined) {
|
||||||
{
|
|
||||||
this.sockets[rChannelId].end();
|
this.sockets[rChannelId].end();
|
||||||
var amtId = this.sockets[rChannelId].lme.amtId;
|
var amtId = this.sockets[rChannelId].lme.amtId;
|
||||||
var buffer = Buffer.alloc(5);
|
var buffer = Buffer.alloc(5);
|
||||||
@ -302,8 +267,7 @@ function lme_heci()
|
|||||||
buffer.writeUInt32BE(amtId, 1);
|
buffer.writeUInt32BE(amtId, 1);
|
||||||
this.write(buffer);
|
this.write(buffer);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
//console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_CLOSE');
|
//console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_CLOSE');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -311,8 +275,7 @@ function lme_heci()
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.bindDuplexStream = function (duplexStream, remoteFamily, localPort)
|
this.bindDuplexStream = function (duplexStream, remoteFamily, localPort) {
|
||||||
{
|
|
||||||
var socket = duplexStream;
|
var socket = duplexStream;
|
||||||
//console.log('New [' + remoteFamily + '] Virtual Connection/' + socket.localPort);
|
//console.log('New [' + remoteFamily + '] Virtual Connection/' + socket.localPort);
|
||||||
socket.pendingBytes = [];
|
socket.pendingBytes = [];
|
||||||
@ -327,15 +290,12 @@ function lme_heci()
|
|||||||
buffer.writeUInt32BE(socket.lme.ourId);
|
buffer.writeUInt32BE(socket.lme.ourId);
|
||||||
buffer.writeUInt32BE(this.INITIAL_RXWINDOW_SIZE);
|
buffer.writeUInt32BE(this.INITIAL_RXWINDOW_SIZE);
|
||||||
buffer.writeUInt32BE(0xFFFFFFFF);
|
buffer.writeUInt32BE(0xFFFFFFFF);
|
||||||
for (var i = 0; i < 2; ++i)
|
for (var i = 0; i < 2; ++i) {
|
||||||
{
|
if (remoteFamily == 'IPv6') {
|
||||||
if (remoteFamily == 'IPv6')
|
|
||||||
{
|
|
||||||
buffer.writeUInt32BE(3);
|
buffer.writeUInt32BE(3);
|
||||||
buffer.write('::1');
|
buffer.write('::1');
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
buffer.writeUInt32BE(9);
|
buffer.writeUInt32BE(9);
|
||||||
buffer.write('127.0.0.1');
|
buffer.write('127.0.0.1');
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ function AMTScanner() {
|
|||||||
server.bind({ address: '0.0.0.0', port: 0, exclusive: true });
|
server.bind({ address: '0.0.0.0', port: 0, exclusive: true });
|
||||||
var tmout = setTimeout(function cb() {
|
var tmout = setTimeout(function cb() {
|
||||||
//console.log("Server closed");
|
//console.log("Server closed");
|
||||||
//server.close();
|
server.close();
|
||||||
server.parent.emit('found', server.scanResults);
|
server.parent.emit('found', server.scanResults);
|
||||||
if (func != null) { func(server.scanResults); }
|
if (func != null) { func(server.scanResults); }
|
||||||
delete server;
|
delete server;
|
||||||
|
@ -123,7 +123,7 @@ function lme_heci()
|
|||||||
|
|
||||||
this._LME = heci.create();
|
this._LME = heci.create();
|
||||||
this._LME.LMS = this;
|
this._LME.LMS = this;
|
||||||
this._LME.on('error', function (e) { this.Parent.emit('error', e); });
|
this._LME.on('error', function (e) { this.LMS.emit('error', e); });
|
||||||
this._LME.on('connect', function ()
|
this._LME.on('connect', function ()
|
||||||
{
|
{
|
||||||
this.LMS.emit('connect');
|
this.LMS.emit('connect');
|
||||||
|
@ -11,6 +11,7 @@ module.exports.CertificateOperations = function () {
|
|||||||
|
|
||||||
obj.fs = require('fs');
|
obj.fs = require('fs');
|
||||||
obj.forge = require('node-forge');
|
obj.forge = require('node-forge');
|
||||||
|
obj.crypto = require('crypto');
|
||||||
obj.pki = obj.forge.pki;
|
obj.pki = obj.forge.pki;
|
||||||
obj.dirExists = function (filePath) { try { return obj.fs.statSync(filePath).isDirectory(); } catch (err) { return false; } }
|
obj.dirExists = function (filePath) { try { return obj.fs.statSync(filePath).isDirectory(); } catch (err) { return false; } }
|
||||||
obj.getFilesizeInBytes = function(filename) { try { return obj.fs.statSync(filename)["size"]; } catch (err) { return -1; } }
|
obj.getFilesizeInBytes = function(filename) { try { return obj.fs.statSync(filename)["size"]; } catch (err) { return -1; } }
|
||||||
@ -412,51 +413,55 @@ module.exports.CertificateOperations = function () {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start accelerators
|
// Accelerators, used to dispatch work to other processes
|
||||||
const fork = require('child_process').fork;
|
const fork = require('child_process').fork;
|
||||||
const program = require('path').resolve('meshaccelerator.js');
|
const program = require('path').join(__dirname, 'meshaccelerator.js');
|
||||||
const acceleratorCreateCount = require('os').cpus().length;
|
const acceleratorTotalCount = require('os').cpus().length;
|
||||||
|
var acceleratorCreateCount = acceleratorTotalCount;
|
||||||
var freeAccelerators = [];
|
var freeAccelerators = [];
|
||||||
|
var pendingAccelerator = [];
|
||||||
|
obj.acceleratorCertStore = null;
|
||||||
|
|
||||||
// Create a new accelerator module
|
// Create a new accelerator module
|
||||||
obj.getAccelerator = function() {
|
obj.getAccelerator = function () {
|
||||||
|
if (obj.acceleratorCertStore == null) { return null; }
|
||||||
if (freeAccelerators.length > 0) { return freeAccelerators.pop(); }
|
if (freeAccelerators.length > 0) { return freeAccelerators.pop(); }
|
||||||
if (acceleratorCreateCount > 0) {
|
if (acceleratorCreateCount > 0) {
|
||||||
|
acceleratorCreateCount--;
|
||||||
var accelerator = fork(program, [], { stdio: ['pipe', 'pipe', 'pipe', 'ipc'] });
|
var accelerator = fork(program, [], { stdio: ['pipe', 'pipe', 'pipe', 'ipc'] });
|
||||||
accelerator.on('message', function (message) { this.func(message); freeAccelerators.push(this); });
|
accelerator.on('message', function (message) { this.func(message); if (pendingAccelerator.length > 0) { accelerator.send(pendingAccelerator.shift()); } else { freeAccelerators.push(this); } });
|
||||||
if (obj.acceleratorCertStore != null) { accelerator.send({ action: 'setState', certs: obj.acceleratorCertStore }); }
|
accelerator.send({ action: 'setState', certs: obj.acceleratorCertStore });
|
||||||
return accelerator;
|
return accelerator;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the state of the accelerators. This way, we don't have to send certificate & keys to them each time.
|
// Set the state of the accelerators. This way, we don't have to send certificate & keys to them each time.
|
||||||
obj.acceleratorCertStore = null;
|
obj.acceleratorStart = function (certificates) {
|
||||||
obj.acceleratorPerformSetState = function (certificates) {
|
if (obj.acceleratorCertStore != null) { console.error('ERROR: Accelerators can only be started once.'); return; }
|
||||||
obj.acceleratorCertStore = [{ cert: certificates.agent.cert, key: certificates.agent.key }];
|
obj.acceleratorCertStore = [{ cert: certificates.agent.cert, key: certificates.agent.key }];
|
||||||
if (certificates.swarmserver != null) { obj.acceleratorCertStore.push({ cert: certificates.swarmserver.cert, key: certificates.swarmserver.key }); }
|
if (certificates.swarmserver != null) { obj.acceleratorCertStore.push({ cert: certificates.swarmserver.cert, key: certificates.swarmserver.key }); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform any RSA signature, just pass in the private key and data.
|
// Perform any RSA signature, just pass in the private key and data.
|
||||||
obj.acceleratorPerformSignature = function (privatekey, data, func) {
|
obj.acceleratorPerformSignature = function (privatekey, data, func) {
|
||||||
var acc = obj.getAccelerator();
|
if (acceleratorTotalCount <= 1) {
|
||||||
if (acc == null) {
|
|
||||||
// No accelerators available
|
// No accelerators available
|
||||||
if (typeof privatekey == 'number') { privatekey = obj.acceleratorCertStore[privatekey].key; }
|
if (typeof privatekey == 'number') { privatekey = obj.acceleratorCertStore[privatekey].key; }
|
||||||
const sign = crypto.createSign('SHA384');
|
const sign = obj.crypto.createSign('SHA384');
|
||||||
sign.end(new Buffer(data, 'binary'));
|
sign.end(new Buffer(data, 'binary'));
|
||||||
func(sign.sign(privatekey).toString('binary'));
|
func(sign.sign(privatekey).toString('binary'));
|
||||||
} else {
|
} else {
|
||||||
// Use the accelerator
|
var acc = obj.getAccelerator();
|
||||||
|
if (acc == null) {
|
||||||
|
// Add to pending accelerator workload
|
||||||
|
pendingAccelerator.push({ action: 'sign', key: privatekey, data: data });
|
||||||
|
} else {
|
||||||
|
// Send to accelerator now
|
||||||
acc.func = func;
|
acc.func = func;
|
||||||
acc.send({ action: 'sign', key: privatekey, data: data });
|
acc.send({ action: 'sign', key: privatekey, data: data });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform a RSA signature. This is time consuming
|
|
||||||
obj.acceleratorPerformVerify = function (publickey, data, msg, func) {
|
|
||||||
console.log('Performing verification...');
|
|
||||||
func(publickey.verify(data, msg));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
|
81
letsEncrypt.js
Normal file
81
letsEncrypt.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* @description MeshCentral letsEncrypt module
|
||||||
|
* @author Ylian Saint-Hilaire
|
||||||
|
* @copyright Intel Corporation 2018
|
||||||
|
* @license Apache-2.0
|
||||||
|
* @version v0.0.1
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports.CreateLetsEncrypt = function (parent) {
|
||||||
|
var obj = {};
|
||||||
|
obj.parent = parent;
|
||||||
|
obj.webrootPath = obj.parent.path.join(obj.parent.datapath, 'acme-challenges');
|
||||||
|
obj.workPath = obj.parent.path.join(obj.parent.datapath, 'acme-challenges', 'work');
|
||||||
|
obj.logsPath = obj.parent.path.join(obj.parent.datapath, 'acme-challenges', 'logs');
|
||||||
|
|
||||||
|
try { obj.parent.fs.mkdirSync(obj.webrootPath); } catch (e) { }
|
||||||
|
try { obj.parent.fs.mkdirSync(obj.workPath); } catch (e) { }
|
||||||
|
try { obj.parent.fs.mkdirSync(obj.logsPath); } catch (e) { }
|
||||||
|
|
||||||
|
console.log('CreateLetsEncrypt-1', obj.webrootPath);
|
||||||
|
console.log('CreateLetsEncrypt-1', obj.workPath);
|
||||||
|
console.log('CreateLetsEncrypt-1', obj.logsPath);
|
||||||
|
|
||||||
|
obj.lex = require('greenlock-express').create({
|
||||||
|
// Set to https://acme-v01.api.letsencrypt.org/directory in production
|
||||||
|
server: 'staging'
|
||||||
|
|
||||||
|
// If you wish to replace the default plugins, you may do so here
|
||||||
|
, challenges: {
|
||||||
|
'http-01': require('le-challenge-fs').create({ webrootPath: obj.webrootPath })
|
||||||
|
}
|
||||||
|
, store: require('le-store-certbot').create({
|
||||||
|
//configDir: '/etc/letsencrypt',
|
||||||
|
//privkeyPath: ':configDir/live/:hostname/privkey.pem',
|
||||||
|
//fullchainPath: ':configDir/live/:hostname/fullchain.pem',
|
||||||
|
//certPath: ':configDir/live/:hostname/cert.pem',
|
||||||
|
//chainPath: ':configDir/live/:hostname/chain.pem',
|
||||||
|
workDir: obj.workPath,
|
||||||
|
logsDir: obj.logsPath,
|
||||||
|
webrootPath: obj.webrootPath,
|
||||||
|
debug: false
|
||||||
|
})
|
||||||
|
, approveDomains: approveDomains
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('CreateLetsEncrypt-2');
|
||||||
|
function approveDomains(opts, certs, func) {
|
||||||
|
console.log('approveDomains', opts, certs);
|
||||||
|
|
||||||
|
// This is where you check your database and associated
|
||||||
|
// email addresses with domains and agreements and such
|
||||||
|
|
||||||
|
|
||||||
|
// The domains being approved for the first time are listed in opts.domains
|
||||||
|
// Certs being renewed are listed in certs.altnames
|
||||||
|
if (certs) {
|
||||||
|
opts.domains = ['example.com', 'yourdomain.com']
|
||||||
|
} else {
|
||||||
|
opts.email = 'john.doe@example.com';
|
||||||
|
opts.agreeTos = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: you can also change other options such as `challengeType` and `challenge`
|
||||||
|
// opts.challengeType = 'http-01';
|
||||||
|
// opts.challenge = require('le-challenge-fs').create({});
|
||||||
|
|
||||||
|
func(null, { options: opts, certs: certs });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handles acme-challenge and redirects to https
|
||||||
|
require('http').createServer(obj.lex.middleware(require('redirect-https')())).listen(81, function () { console.log("Listening for ACME http-01 challenges on", this.address()); });
|
||||||
|
|
||||||
|
var app = require('express')();
|
||||||
|
app.use('/', function (req, res) { res.end('Hello, World!'); });
|
||||||
|
|
||||||
|
// Handles your app
|
||||||
|
require('https').createServer(obj.lex.httpsOptions, obj.lex.middleware(app)).listen(443, function () { console.log("Listening for ACME tls-sni-01 challenges and serve app on", this.address()); });
|
||||||
|
|
||||||
|
console.log('CreateLetsEncrypt-3');
|
||||||
|
return obj;
|
||||||
|
}
|
22
meshagent.js
22
meshagent.js
@ -170,7 +170,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
|||||||
obj.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.parent.swarmCertificateAsn1.length) + obj.parent.swarmCertificateAsn1 + signature); // Command 2, certificate + signature
|
obj.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.parent.swarmCertificateAsn1.length) + obj.parent.swarmCertificateAsn1 + signature); // Command 2, certificate + signature
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Perform the hash signature using new server agent certificate
|
// Perform the hash signature using the server agent certificate
|
||||||
obj.parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, function (signature) {
|
obj.parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, function (signature) {
|
||||||
// Send back our certificate + signature
|
// Send back our certificate + signature
|
||||||
obj.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.parent.agentCertificateAsn1.length) + obj.parent.agentCertificateAsn1 + signature); // Command 2, certificate + signature
|
obj.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.parent.agentCertificateAsn1.length) + obj.parent.agentCertificateAsn1 + signature); // Command 2, certificate + signature
|
||||||
@ -190,9 +190,8 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
|||||||
// Decode the certificate
|
// Decode the certificate
|
||||||
var certlen = obj.common.ReadShort(msg, 2);
|
var certlen = obj.common.ReadShort(msg, 2);
|
||||||
obj.unauth = {};
|
obj.unauth = {};
|
||||||
obj.unauth.nodeCert = null;
|
try { obj.unauth.nodeid = new Buffer(obj.forge.pki.getPublicKeyFingerprint(obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(msg.substring(4, 4 + certlen))).publicKey, { md: obj.forge.md.sha384.create() }).data, 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); } catch (e) { return; }
|
||||||
try { obj.unauth.nodeCert = obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(msg.substring(4, 4 + certlen))); } catch (e) { return; }
|
obj.unauth.nodeCertPem = '-----BEGIN CERTIFICATE-----\r\n' + new Buffer(msg.substring(4, 4 + certlen), 'binary').toString('base64') + '\r\n-----END CERTIFICATE-----';
|
||||||
obj.unauth.nodeid = new Buffer(obj.forge.pki.getPublicKeyFingerprint(obj.unauth.nodeCert.publicKey, { md: obj.forge.md.sha384.create() }).data, 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
|
||||||
|
|
||||||
// Check the agent signature if we can
|
// Check the agent signature if we can
|
||||||
if (obj.agentnonce == null) { obj.unauthsign = msg.substring(4 + certlen); } else { if (processAgentSignature(msg.substring(4 + certlen)) == false) { console.log('Agent connected with bad signature, holding connection (' + obj.remoteaddr + ').'); return; } }
|
if (obj.agentnonce == null) { obj.unauthsign = msg.substring(4 + certlen); } else { if (processAgentSignature(msg.substring(4 + certlen)) == false) { console.log('Agent connected with bad signature, holding connection (' + obj.remoteaddr + ').'); return; } }
|
||||||
@ -237,7 +236,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
|||||||
|
|
||||||
// Start authenticate the mesh agent by sending a auth nonce & server TLS cert hash.
|
// Start authenticate the mesh agent by sending a auth nonce & server TLS cert hash.
|
||||||
// Send 384 bits SHA384 hash of TLS cert public key + 384 bits nonce
|
// Send 384 bits SHA384 hash of TLS cert public key + 384 bits nonce
|
||||||
obj.nonce = obj.forge.random.getBytesSync(48);
|
obj.nonce = obj.parent.crypto.randomBytes(48).toString('binary');
|
||||||
obj.send(obj.common.ShortToStr(1) + getWebCertHash(obj.domain) + obj.nonce); // Command 1, hash + nonce
|
obj.send(obj.common.ShortToStr(1) + getWebCertHash(obj.domain) + obj.nonce); // Command 1, hash + nonce
|
||||||
|
|
||||||
// Once we get all the information about an agent, run this to hook everything up to the server
|
// Once we get all the information about an agent, run this to hook everything up to the server
|
||||||
@ -357,18 +356,17 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
|||||||
|
|
||||||
// Get the web certificate hash for the speficied domain
|
// Get the web certificate hash for the speficied domain
|
||||||
function getWebCertHash(domain) {
|
function getWebCertHash(domain) {
|
||||||
//var hash = obj.parent.webCertificateHashs[domain.id];
|
var hash = obj.parent.webCertificateHashs[domain.id];
|
||||||
//if (hash == null) return obj.parent.webCertificateHash; else return hash;
|
if (hash != null) return hash;
|
||||||
return obj.parent.webCertificateHash;
|
return obj.parent.webCertificateHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the agent signature
|
// Verify the agent signature
|
||||||
function processAgentSignature(msg) {
|
function processAgentSignature(msg) {
|
||||||
var md = obj.forge.md.sha384.create(); // TODO: Switch this to SHA384 on node instead of forge.
|
// Verify the signature. This is the fast way, without using forge.
|
||||||
md.update(getWebCertHash(obj.domain), 'binary');
|
const verify = obj.parent.crypto.createVerify('SHA384');
|
||||||
md.update(obj.nonce, 'binary');
|
verify.end(new Buffer(getWebCertHash(obj.domain) + obj.nonce + obj.agentnonce, 'binary'));
|
||||||
md.update(obj.agentnonce, 'binary');
|
if (verify.verify(obj.unauth.nodeCertPem, new Buffer(msg, 'binary')) !== true) { return false; }
|
||||||
if (obj.unauth.nodeCert.publicKey.verify(md.digest().bytes(), msg) == false) { return false; } // TODO: Check if this is slow or not. May n
|
|
||||||
|
|
||||||
// Connection is a success, clean up
|
// Connection is a success, clean up
|
||||||
obj.nodeid = obj.unauth.nodeid;
|
obj.nodeid = obj.unauth.nodeid;
|
||||||
|
@ -314,7 +314,7 @@ function CreateMeshCentralServer() {
|
|||||||
obj.certificateOperations = require('./certoperations.js').CertificateOperations()
|
obj.certificateOperations = require('./certoperations.js').CertificateOperations()
|
||||||
obj.certificateOperations.GetMeshServerCertificate(obj.datapath, obj.args, obj.config, function (certs) {
|
obj.certificateOperations.GetMeshServerCertificate(obj.datapath, obj.args, obj.config, function (certs) {
|
||||||
obj.certificates = certs;
|
obj.certificates = certs;
|
||||||
obj.certificateOperations.acceleratorPerformSetState(certs); // Set the state of the accelerators
|
obj.certificateOperations.acceleratorStart(certs); // Set the state of the accelerators
|
||||||
|
|
||||||
// If the certificate is un-configured, force LAN-only mode
|
// If the certificate is un-configured, force LAN-only mode
|
||||||
if (obj.certificates.CommonName == 'un-configured') { console.log('Server name not configured, running in LAN-only mode.'); obj.args.lanonly = true; }
|
if (obj.certificates.CommonName == 'un-configured') { console.log('Server name not configured, running in LAN-only mode.'); obj.args.lanonly = true; }
|
||||||
|
@ -29,7 +29,6 @@ module.exports.CreateMultiServer = function (parent, args) {
|
|||||||
obj.common = require('./common.js');
|
obj.common = require('./common.js');
|
||||||
obj.forge = require('node-forge');
|
obj.forge = require('node-forge');
|
||||||
obj.crypto = require('crypto');
|
obj.crypto = require('crypto');
|
||||||
obj.pki = obj.forge.pki;
|
|
||||||
obj.connectionState = 0;
|
obj.connectionState = 0;
|
||||||
obj.retryTimer = null;
|
obj.retryTimer = null;
|
||||||
obj.retryBackoff = 0;
|
obj.retryBackoff = 0;
|
||||||
@ -64,7 +63,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
|||||||
obj.ws.on('open', function () {
|
obj.ws.on('open', function () {
|
||||||
obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Connected');
|
obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Connected');
|
||||||
obj.connectionState |= 2;
|
obj.connectionState |= 2;
|
||||||
obj.nonce = obj.forge.random.getBytesSync(48);
|
obj.nonce = obj.crypto.randomBytes(48).toString('binary');
|
||||||
|
|
||||||
// Get the peer server's certificate and compute the server public key hash
|
// Get the peer server's certificate and compute the server public key hash
|
||||||
if (obj.ws._socket == null) return;
|
if (obj.ws._socket == null) return;
|
||||||
@ -94,30 +93,27 @@ module.exports.CreateMultiServer = function (parent, args) {
|
|||||||
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(1, 'OutPeer: Server hash mismatch.'); disconnect(); return; }
|
||||||
obj.servernonce = msg.substring(50);
|
obj.servernonce = msg.substring(50);
|
||||||
|
|
||||||
// Use our agent certificate root private key to sign the ServerHash + ServerNonce + PeerNonce
|
// Perform the hash signature using the server agent certificate
|
||||||
var md = obj.forge.md.sha384.create();
|
obj.parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, function (signature) {
|
||||||
md.update(msg.substring(2), 'binary');
|
|
||||||
md.update(obj.nonce, 'binary');
|
|
||||||
|
|
||||||
// Send back our certificate + signature
|
// Send back our certificate + signature
|
||||||
agentRootCertificateAsn1 = obj.forge.asn1.toDer(obj.forge.pki.certificateToAsn1(obj.certificates.agent.fcert)).getBytes();
|
obj.ws.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.agentCertificateAsn1.length) + obj.agentCertificateAsn1 + signature); // Command 2, certificate + signature
|
||||||
obj.ws.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(agentRootCertificateAsn1.length) + agentRootCertificatAsn1 + obj.certificates.agent.fkey.sign(md)); // Command 3, signature
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2: {
|
case 2: {
|
||||||
// Server certificate
|
// Server certificate
|
||||||
var certlen = obj.common.ReadShort(msg, 2), serverCert = null;
|
var certlen = obj.common.ReadShort(msg, 2), serverCert = null;
|
||||||
|
var serverCertPem = '-----BEGIN CERTIFICATE-----\r\n' + new Buffer(msg.substring(4, 4 + certlen), 'binary').toString('base64') + '\r\n-----END CERTIFICATE-----';
|
||||||
try { serverCert = obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(msg.substring(4, 4 + certlen))); } catch (e) { }
|
try { serverCert = obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(msg.substring(4, 4 + certlen))); } catch (e) { }
|
||||||
if (serverCert == null) { obj.parent.parent.debug(1, 'OutPeer: Invalid server certificate.'); disconnect(); return; }
|
if (serverCert == null) { obj.parent.parent.debug(1, 'OutPeer: Invalid server certificate.'); disconnect(); return; }
|
||||||
var serverid = new Buffer(obj.forge.pki.getPublicKeyFingerprint(serverCert.publicKey, { encoding: 'binary', md: obj.forge.md.sha384.create() }), 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
var serverid = new Buffer(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(1, 'OutPeer: Server hash mismatch.'); disconnect(); return; }
|
||||||
|
|
||||||
// Server signature, verify it
|
// Server signature, verify it. This is the fast way, without using forge. (TODO: Use accelerator for this?)
|
||||||
var md = obj.forge.md.sha384.create();
|
const verify = obj.parent.crypto.createVerify('SHA384');
|
||||||
md.update(obj.serverCertHash, 'binary');
|
verify.end(new Buffer(obj.serverCertHash + obj.nonce + obj.servernonce, 'binary'));
|
||||||
md.update(obj.nonce, 'binary');
|
if (verify.verify(serverCertPem, new Buffer(msg.substring(4 + certlen), 'binary')) !== true) { obj.parent.parent.debug(1, 'OutPeer: Server sign check failed.'); disconnect(); return; }
|
||||||
md.update(obj.servernonce, 'binary');
|
|
||||||
if (serverCert.publicKey.verify(md.digest().bytes(), msg.substring(4 + certlen)) == false) { obj.parent.parent.debug(1, 'OutPeer: Server sign check failed.'); disconnect(); return; }
|
|
||||||
|
|
||||||
// Connection is a success, clean up
|
// Connection is a success, clean up
|
||||||
delete obj.nonce;
|
delete obj.nonce;
|
||||||
@ -128,14 +124,14 @@ module.exports.CreateMultiServer = function (parent, args) {
|
|||||||
obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Verified peer connection to ' + obj.url);
|
obj.parent.parent.debug(1, 'OutPeer ' + obj.serverid + ': Verified peer connection to ' + obj.url);
|
||||||
|
|
||||||
// Send information about our server to the peer
|
// Send information about our server to the peer
|
||||||
if (obj.connectionState == 15) { obj.ws.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.parent.webserver.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 })); }
|
if (obj.connectionState == 15) { obj.ws.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.parent.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 })); }
|
||||||
//if ((obj.connectionState == 15) && (obj.connectHandler != null)) { obj.connectHandler(1); }
|
//if ((obj.connectionState == 15) && (obj.connectHandler != null)) { obj.connectHandler(1); }
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 4: {
|
case 4: {
|
||||||
// Server confirmed authentication, we are allowed to send commands to the server
|
// Server confirmed authentication, we are allowed to send commands to the server
|
||||||
obj.connectionState |= 8;
|
obj.connectionState |= 8;
|
||||||
if (obj.connectionState == 15) { obj.ws.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.parent.webserver.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 })); }
|
if (obj.connectionState == 15) { obj.ws.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.parent.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 })); }
|
||||||
//if ((obj.connectionState == 15) && (obj.connectHandler != null)) { obj.connectHandler(1); }
|
//if ((obj.connectionState == 15) && (obj.connectHandler != null)) { obj.connectHandler(1); }
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -258,15 +254,13 @@ module.exports.CreateMultiServer = function (parent, args) {
|
|||||||
|
|
||||||
// Check that the server hash matches out own web certificate hash
|
// Check that the server hash matches out own web certificate hash
|
||||||
if (obj.webCertificateHash != msg.substring(2, 50)) { obj.close(); return; }
|
if (obj.webCertificateHash != msg.substring(2, 50)) { obj.close(); return; }
|
||||||
|
|
||||||
// Use our server private key to sign the ServerHash + PeerNonce + ServerNonce
|
|
||||||
var md = obj.forge.md.sha384.create();
|
|
||||||
md.update(msg.substring(2), 'binary');
|
|
||||||
md.update(obj.nonce, 'binary');
|
|
||||||
obj.peernonce = msg.substring(50);
|
obj.peernonce = msg.substring(50);
|
||||||
|
|
||||||
|
// Perform the hash signature using the server agent certificate
|
||||||
|
obj.parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, function (signature) {
|
||||||
// Send back our certificate + signature
|
// Send back our certificate + signature
|
||||||
obj.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.agentCertificateAsn1.length) + obj.agentCertificateAsn1 + obj.parent.parent.certificates.agent.fkey.sign(md)); // Command 2, certificate + signature
|
obj.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.agentCertificateAsn1.length) + obj.agentCertificateAsn1 + signature); // Command 2, certificate + signature
|
||||||
|
});
|
||||||
|
|
||||||
// Check the peer server signature if we can
|
// Check the peer server signature if we can
|
||||||
if (obj.unauthsign != null) {
|
if (obj.unauthsign != null) {
|
||||||
@ -275,22 +269,25 @@ module.exports.CreateMultiServer = function (parent, args) {
|
|||||||
}
|
}
|
||||||
else if (cmd == 2) {
|
else if (cmd == 2) {
|
||||||
// Peer server certificate
|
// Peer server certificate
|
||||||
if ((msg.length < 4) || ((obj.receivedCommands & 2) != 0)) return;
|
if ((msg.length < 4) || ((obj.receivedCommands & 2) != 0)) { obj.parent.parent.debug(1, 'InPeer: Invalid command 2.'); return; }
|
||||||
obj.receivedCommands += 2; // Peer server can't send the same command twice on the same connection ever. Block DOS attack path.
|
obj.receivedCommands += 2; // Peer server can't send the same command twice on the same connection ever. Block DOS attack path.
|
||||||
|
|
||||||
// Decode the certificate
|
// Decode the certificate
|
||||||
var certlen = obj.common.ReadShort(msg, 2);
|
var certlen = obj.common.ReadShort(msg, 2);
|
||||||
obj.unauth = {};
|
obj.unauth = {};
|
||||||
obj.unauth.nodeCert = null;
|
try { obj.unauth.nodeid = new Buffer(obj.forge.pki.getPublicKeyFingerprint(obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(msg.substring(4, 4 + certlen))).publicKey, { encoding: 'binary', md: obj.forge.md.sha384.create() }), 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); } catch (e) { console.log(e); return; }
|
||||||
try { obj.unauth.nodeCert = obj.forge.pki.certificateFromAsn1(obj.forge.asn1.fromDer(msg.substring(4, 4 + certlen))); } catch (e) { return; }
|
obj.unauth.nodeCertPem = '-----BEGIN CERTIFICATE-----\r\n' + new Buffer(msg.substring(4, 4 + certlen), 'binary').toString('base64') + '\r\n-----END CERTIFICATE-----';
|
||||||
obj.unauth.nodeid = new Buffer(obj.forge.pki.getPublicKeyFingerprint(obj.unauth.nodeCert.publicKey, { encoding: 'binary', md: obj.forge.md.sha384.create() }), 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
|
||||||
|
|
||||||
// Check the peer server signature if we can
|
// Check the peer server signature if we can
|
||||||
if (obj.peernonce == null) { obj.unauthsign = msg.substring(4 + certlen); } else { if (processPeerSignature(msg.substring(4 + certlen)) == false) { obj.close(); return; } }
|
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; }
|
||||||
|
}
|
||||||
completePeerServerConnection();
|
completePeerServerConnection();
|
||||||
}
|
}
|
||||||
else if (cmd == 3) {
|
else if (cmd == 3) {
|
||||||
if ((msg.length < 56) || ((obj.receivedCommands & 4) != 0)) return;
|
if ((msg.length < 56) || ((obj.receivedCommands & 4) != 0)) { obj.parent.parent.debug(1, 'InPeer: Invalid command 3.'); return; }
|
||||||
obj.receivedCommands += 4; // Peer server can't send the same command twice on the same connection ever. Block DOS attack path.
|
obj.receivedCommands += 4; // Peer server can't send the same command twice on the same connection ever. Block DOS attack path.
|
||||||
completePeerServerConnection();
|
completePeerServerConnection();
|
||||||
}
|
}
|
||||||
@ -306,25 +303,24 @@ module.exports.CreateMultiServer = function (parent, args) {
|
|||||||
|
|
||||||
// Start authenticate the peer server by sending a auth nonce & server TLS cert hash.
|
// Start authenticate the peer server by sending a auth nonce & server TLS cert hash.
|
||||||
// Send 384 bits SHA382 hash of TLS cert public key + 384 bits nonce
|
// Send 384 bits SHA382 hash of TLS cert public key + 384 bits nonce
|
||||||
obj.nonce = obj.forge.random.getBytesSync(48);
|
obj.nonce = obj.crypto.randomBytes(48).toString('binary');
|
||||||
obj.send(obj.common.ShortToStr(1) + obj.webCertificateHash + obj.nonce); // Command 1, hash + nonce
|
obj.send(obj.common.ShortToStr(1) + obj.webCertificateHash + obj.nonce); // Command 1, hash + nonce
|
||||||
|
|
||||||
// Once we get all the information about an peer server, run this to hook everything up to the server
|
// Once we get all the information about an peer server, run this to hook everything up to the server
|
||||||
function completePeerServerConnection() {
|
function completePeerServerConnection() {
|
||||||
if (obj.authenticated != 1) return;
|
if (obj.authenticated != 1) return;
|
||||||
obj.send(obj.common.ShortToStr(4));
|
obj.send(obj.common.ShortToStr(4));
|
||||||
obj.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.parent.webserver.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 }));
|
obj.send(JSON.stringify({ action: 'info', serverid: obj.parent.serverid, dbid: obj.parent.parent.db.identifier, key: obj.parent.parent.serverKey.toString('hex'), serverCertHash: obj.parent.parent.webserver.webCertificateHashBase64 }));
|
||||||
obj.authenticated = 2;
|
obj.authenticated = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the peer server signature
|
// Verify the peer server signature
|
||||||
function processPeerSignature(msg) {
|
function processPeerSignature(msg) {
|
||||||
var md = obj.forge.md.sha384.create(); // TODO: Switch this to SHA384 on node instead of forge.
|
// Verify the signature. This is the fast way, without using forge.
|
||||||
md.update(obj.parent.parent.webserver.webCertificateHash, 'binary');
|
const verify = obj.parent.crypto.createVerify('SHA384');
|
||||||
md.update(obj.nonce, 'binary');
|
verify.end(new Buffer(obj.parent.parent.webserver.webCertificateHash + obj.nonce + obj.peernonce, 'binary'));
|
||||||
md.update(obj.peernonce, 'binary');
|
if (verify.verify(obj.unauth.nodeCertPem, new Buffer(msg, 'binary')) !== true) { console.log('Peer sign fail 1'); return false; }
|
||||||
if (obj.unauth.nodeCert.publicKey.verify(md.digest().bytes(), msg) == false) { return false; }
|
if (obj.unauth.nodeid !== obj.agentCertificateHashBase64) { console.log('Peer sign fail 2'); return false; }
|
||||||
if (obj.unauth.nodeid !== obj.agentCertificateHashBase64) { return false; }
|
|
||||||
|
|
||||||
// Connection is a success, clean up
|
// Connection is a success, clean up
|
||||||
obj.nodeid = obj.unauth.nodeid;
|
obj.nodeid = obj.unauth.nodeid;
|
||||||
@ -333,6 +329,7 @@ module.exports.CreateMultiServer = function (parent, args) {
|
|||||||
delete obj.unauth;
|
delete obj.unauth;
|
||||||
if (obj.unauthsign) delete obj.unauthsign;
|
if (obj.unauthsign) delete obj.unauthsign;
|
||||||
obj.authenticated = 1;
|
obj.authenticated = 1;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "meshcentral",
|
"name": "meshcentral",
|
||||||
"version": "0.1.2-b",
|
"version": "0.1.2-h",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Remote Management",
|
"Remote Management",
|
||||||
"Intel AMT",
|
"Intel AMT",
|
||||||
|
Loading…
Reference in New Issue
Block a user