Fixed CIRA connections when a device is moved to a different group.
Ylian Saint-Hilaire committed
Oct 10, 2019 at 16:07 UTC
6165723ef124c1952002c5b128c6c8885211dd52
4 files changed
+87
-62
db.js
+4
-2
@@ -671,7 +671,8 @@ module.exports.CreateDB = function (parent, func) {
671
};
672
obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } };
673
obj.getLocalAmtNodes = function (func) { obj.file.find({ type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }).toArray(func); };
674
- obj.getAmtUuidNode = function (meshid, uuid, func) { obj.file.find({ type: 'node', meshid: meshid, 'intelamt.uuid': uuid }).toArray(func); };
674
+ obj.getAmtUuidMeshNode = function (meshid, uuid, func) { obj.file.find({ type: 'node', meshid: meshid, 'intelamt.uuid': uuid }).toArray(func); };
675
+ obj.getAmtUuidNode = function (uuid, func) { obj.file.find({ type: 'node', 'intelamt.uuid': uuid }).toArray(func); };
676
677
// TODO: Starting in MongoDB 4.0.3, you should use countDocuments() instead of count() that is deprecated. We should detect MongoDB version and switch.
678
// https://docs.mongodb.com/manual/reference/method/db.collection.countDocuments/
@@ -794,7 +795,8 @@ module.exports.CreateDB = function (parent, func) {
795
};
796
obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } };
797
obj.getLocalAmtNodes = function (func) { obj.file.find({ type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }, func); };
797
- obj.getAmtUuidNode = function (meshid, uuid, func) { obj.file.find({ type: 'node', meshid: meshid, 'intelamt.uuid': uuid }, func); };
798
+ obj.getAmtUuidMeshNode = function (meshid, uuid, func) { obj.file.find({ type: 'node', meshid: meshid, 'intelamt.uuid': uuid }, func); };
799
+ obj.getAmtUuidNode = function (uuid, func) { obj.file.find({ type: 'node', 'intelamt.uuid': uuid }, func); };
800
obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.count({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max), count); }); } }
801
802
// Database actions on the events collection
meshuser.js
+3
@@ -2017,6 +2017,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2017
// If any MQTT sessions are connected on this server, switch it now.
2018
if (parent.parent.mqttbroker != null) { parent.parent.mqttbroker.changeDeviceMesh(node._id, command.meshid); }
2019
2020
+ // If any CIRA sessions are connected on this server, switch it now.
2021
+ if (parent.parent.mpsserver != null) { parent.parent.mpsserver.changeDeviceMesh(node._id, command.meshid); }
2022
+
2023
// Add the connection state
2024
const state = parent.parent.GetConnectivityState(node._id);
2025
if (state) {
mpsserver.js
+79
-59
@@ -20,7 +20,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
20
obj.db = db;
21
obj.args = args;
22
obj.certificates = certificates;
23
- obj.ciraConnections = {};
23
+ obj.ciraConnections = {}; // NodeID --> Socket
24
var tlsSessionStore = {}; // Store TLS session information for quick resume.
25
var tlsSessionStoreCount = 0; // Number of cached TLS session information in store.
26
const constants = (require('crypto').constants ? require('crypto').constants : require('constants')); // require('constants') is deprecated in Node 11.10, use require('crypto').constants instead.
@@ -272,41 +272,26 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
272
socket.tag.connectTime = Date.now();
273
socket.tag.host = '';
274
275
- // Fetch the mesh
276
- obj.db.Get(socket.tag.meshid, function (err, meshes) {
277
- if ((meshes != null) && (meshes.length === 1)) {
278
- var mesh = meshes[0];
279
- obj.db.Get(socket.tag.nodeid, function (err, nodes) {
280
- if ((nodes == null) || (nodes.length !== 1)) {
281
- if (mesh.mtype == 1) {
282
- // Check if we already have too many devices for this domain
283
- if (domain.limits && (typeof domain.limits.maxdevices == 'number')) {
284
- db.isMaxType(domain.limits.maxdevices, 'node', domain.id, function (ismax, count) {
285
- if (ismax == true) {
286
- // Too many devices in this domain.
287
- maxDomainDevicesReached++;
288
- console.log('Too many devices on this domain to accept the CIRA connection. meshid: ' + socket.tag.meshid);
289
- socket.end();
290
- } else {
291
- // We are under the limit, create the new device.
292
- // Node is not in the database, add it. Credentials will be empty until added by the user.
293
- var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: domainid, intelamt: { user: '', pass: '', tls: 0, state: 2 } };
294
- obj.db.Set(device);
295
-
296
- // Event the new node
297
- addedTlsDeviceCount++;
298
- var device2 = common.Clone(device);
299
- if (device2.intelamt.pass != null) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
300
- var change = 'CIRA added device ' + socket.tag.name + ' to mesh ' + mesh.name;
301
- obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: domainid });
302
-
303
- // Add the connection to the MPS connection list
304
- obj.ciraConnections[socket.tag.nodeid] = socket;
305
- obj.parent.SetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, 2, 7); // TODO: Right now report power state as "present" (7) until we can poll.
306
- }
307
- });
308
- return;
275
+ // Fetch the node
276
+ obj.db.Get(socket.tag.nodeid, function (err, nodes) {
277
+ if ((nodes == null) || (nodes.length !== 1)) {
278
+ var mesh = obj.parent.webserver.meshes[socket.tag.meshid];
279
+ if (mesh == null) {
280
+ unknownTlsMeshIdCount++;
281
+ console.log('ERROR: Intel AMT CIRA connected with unknown groupid: ' + socket.tag.meshid);
282
+ socket.end();
283
+ return;
284
+ } else if (mesh.mtype == 1) {
285
+ // Check if we already have too many devices for this domain
286
+ if (domain.limits && (typeof domain.limits.maxdevices == 'number')) {
287
+ db.isMaxType(domain.limits.maxdevices, 'node', domain.id, function (ismax, count) {
288
+ if (ismax == true) {
289
+ // Too many devices in this domain.
290
+ maxDomainDevicesReached++;
291
+ console.log('Too many devices on this domain to accept the CIRA connection. meshid: ' + socket.tag.meshid);
292
+ socket.end();
293
} else {
294
+ // We are under the limit, create the new device.
295
// Node is not in the database, add it. Credentials will be empty until added by the user.
296
var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: domainid, intelamt: { user: '', pass: '', tls: 0, state: 2 } };
297
obj.db.Set(device);
@@ -317,30 +302,42 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
302
if (device2.intelamt.pass != null) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
303
var change = 'CIRA added device ' + socket.tag.name + ' to mesh ' + mesh.name;
304
obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: domainid });
305
+
306
+ // Add the connection to the MPS connection list
307
+ obj.ciraConnections[socket.tag.nodeid] = socket;
308
+ obj.parent.SetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, 2, 7); // TODO: Right now report power state as "present" (7) until we can poll.
309
}
321
- } else {
322
- // New CIRA connection for unknown node, disconnect.
323
- unknownTlsNodeCount++;
324
- console.log('CIRA connection for unknown node with incorrect group type. meshid: ' + socket.tag.meshid);
325
- socket.end();
326
- return;
327
- }
310
+ });
311
+ return;
312
} else {
329
- // Node is already present
330
- var node = nodes[0];
331
- if ((node.intelamt != null) && (node.intelamt.state == 2)) { socket.tag.host = node.intelamt.host; }
332
- }
313
+ // Node is not in the database, add it. Credentials will be empty until added by the user.
314
+ var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: domainid, intelamt: { user: '', pass: '', tls: 0, state: 2 } };
315
+ obj.db.Set(device);
316
334
- // Add the connection to the MPS connection list
335
- obj.ciraConnections[socket.tag.nodeid] = socket;
336
- obj.parent.SetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, 2, 7); // TODO: Right now report power state as "present" (7) until we can poll.
337
- });
317
+ // Event the new node
318
+ addedTlsDeviceCount++;
319
+ var device2 = common.Clone(device);
320
+ if (device2.intelamt.pass != null) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
321
+ var change = 'CIRA added device ' + socket.tag.name + ' to mesh ' + mesh.name;
322
+ obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: domainid });
323
+ }
324
+ } else {
325
+ // New CIRA connection for unknown node, disconnect.
326
+ unknownTlsNodeCount++;
327
+ console.log('CIRA connection for unknown node with incorrect group type. meshid: ' + socket.tag.meshid);
328
+ socket.end();
329
+ return;
330
+ }
331
} else {
339
- unknownTlsMeshIdCount++;
340
- console.log('ERROR: Intel AMT CIRA connected with unknown groupid: ' + socket.tag.meshid);
341
- socket.end();
342
- return;
332
+ // Node is already present
333
+ var node = nodes[0];
334
+ socket.tag.meshid = node.meshid; // Correct the MeshID if the node has moved.
335
+ if ((node.intelamt != null) && (node.intelamt.state == 2)) { socket.tag.host = node.intelamt.host; }
336
}
337
+
338
+ // Add the connection to the MPS connection list
339
+ obj.ciraConnections[socket.tag.nodeid] = socket;
340
+ obj.parent.SetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, 2, 7); // TODO: Right now report power state as "present" (7) until we can poll.
341
});
342
} else {
343
// This node connected without certificate authentication, use password auth
@@ -410,7 +407,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
407
if (usernameLen != 16) { badUserNameLengthCount++; parent.debug('mps', 'Username length not 16', username, password); SendUserAuthFail(socket); return -1; }
408
var meshIdStart = '/' + username, mesh = null;
409
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; } } }
413
- if (mesh == null) { meshNotFoundCount++; parent.debug('mps', 'Mesh not found', username, password); SendUserAuthFail(socket); return -1; }
410
+ if (mesh == null) { meshNotFoundCount++; parent.debug('mps', 'Device group not found', username, password); SendUserAuthFail(socket); return -1; }
411
412
// If this is a agent-less mesh, use the device guid 3 times as ID.
413
if (mesh.mtype == 1) {
@@ -470,6 +467,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
467
} else {
468
// Node is already present
469
var node = nodes[0];
470
+ socket.tag.meshid = node.meshid; // Correct the MeshID if the node has moved.
471
if ((node.intelamt != null) && (node.intelamt.state == 2)) { socket.tag.host = node.intelamt.host; }
472
}
473
@@ -480,8 +478,8 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
478
});
479
} else if (mesh.mtype == 2) { // If this is a agent mesh, search the mesh for this device UUID
480
// Intel AMT GUID (socket.tag.SystemId) will be used to search the node
483
- obj.db.getAmtUuidNode(mesh._id, socket.tag.SystemId, function (err, nodes) { // TODO: May need to optimize this request with indexes
484
- if ((nodes == null) || (nodes.length !== 1)) {
481
+ obj.db.getAmtUuidNode(socket.tag.SystemId, function (err, nodes) { // TODO: May need to optimize this request with indexes
482
+ if ((nodes == null) || (nodes.length === 0) || (obj.parent.webserver.meshes == null)) {
483
// New CIRA connection for unknown node, disconnect.
484
unknownNodeCount++;
485
console.log('CIRA connection for unknown node. groupid: ' + mesh._id + ', uuid: ' + socket.tag.SystemId);
@@ -489,11 +487,27 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
487
return;
488
}
489
490
+ // Looking at nodes that match this UUID, select one in the same domain and mesh type.
491
+ var node = null;
492
+ for (var i in nodes) {
493
+ if (mesh.domain == nodes[i].domain) {
494
+ var nodemesh = obj.parent.webserver.meshes[nodes[i].meshid];
495
+ if ((nodemesh != null) && (nodemesh.mtype == 2)) { node = nodes[i]; }
496
+ }
497
+ }
498
+
499
+ if (node == null) {
500
+ // New CIRA connection for unknown node, disconnect.
501
+ unknownNodeCount++;
502
+ console.log('CIRA connection for unknown node. candidate(s): ' + nodes.length + ', groupid: ' + mesh._id + ', uuid: ' + socket.tag.SystemId);
503
+ socket.end();
504
+ return;
505
+ }
506
+
507
// Node is present
493
- var node = nodes[0];
508
if ((node.intelamt != null) && (node.intelamt.state == 2)) { socket.tag.host = node.intelamt.host; }
509
socket.tag.nodeid = node._id;
496
- socket.tag.meshid = mesh._id;
510
+ socket.tag.meshid = node.meshid; // Correct the MeshID if the node has moved.
511
socket.tag.connectTime = Date.now();
512
513
// Add the connection to the MPS connection list
@@ -920,6 +934,12 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
934
});
935
}
936
937
+ // Change a node to a new meshid, this is called when a node changes groups.
938
+ obj.changeDeviceMesh = function (nodeid, newMeshId) {
939
+ var socket = obj.ciraConnections[nodeid];
940
+ if ((socket != null) && (socket.tag != null)) { socket.tag.meshid = newMeshId; }
941
+ }
942
+
943
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); }
944
945
return obj;
package.json
+1
-1
@@ -1,6 +1,6 @@
1
{
2
"name": "meshcentral",
3
- "version": "0.4.2-d",
3
+ "version": "0.4.2-e",
4
"keywords": [
5
"Remote Management",
6
"Intel AMT",