Many Intel AMT improvements.

Ylian Saint-Hilaire committed Oct 9, 2020 at 15:44 UTC c0018bb4673348073619f4c8de9d68ecd8f65c03
12 files changed +307 -155
MeshCentralServer.njsproj
-1
@@ -100,7 +100,6 @@
100 <Compile Include="amt\amt-wsman.js" />
101 <Compile Include="amt\amt-xml.js" />
102 <Compile Include="amt\amt.js" />
103 - <Compile Include="apfserver.js" />
103 <Compile Include="exeHandler.js" />
104 <Compile Include="letsencrypt.js" />
105 <Compile Include="mcrec.js" />
agents/meshcore.js
+17 -20
@@ -3507,15 +3507,20 @@ function createMeshCore(agent) {
3507 mpskeepalive: 60000,
3508 clientname: require('os').hostname(),
3509 clientaddress: '127.0.0.1',
3510 - clientuuid: meshCoreObj.intelamt.uuid
3510 + clientuuid: meshCoreObj.intelamt.uuid,
3511 + conntype: 2 // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay, other values for testing.
3512 };
3512 - var tobj = { debug: false }; //
3513 - apftunnel = require('apfclient')(tobj, apfarg);
3514 - try {
3515 - apftunnel.connect();
3516 - response += "..success";
3517 - } catch (e) {
3518 - response += JSON.stringify(e);
3513 + if ((apfarg.clientuuid == null) || (apfarg.clientuuid.length != 36)) {
3514 + response = "Unable to get Intel AMT UUID: " + apfarg.clientuuid;
3515 + } else {
3516 + var tobj = { debug: false };
3517 + apftunnel = require('apfclient')(tobj, apfarg);
3518 + try {
3519 + apftunnel.connect();
3520 + response += "...success";
3521 + } catch (e) {
3522 + response += JSON.stringify(e);
3523 + }
3524 }
3525 } else if (args['_'][0] == 'off') {
3526 response = "Stopping APF tunnel";
@@ -3640,18 +3645,10 @@ function createMeshCore(agent) {
3645 {
3646 switch(amt.lmsstate)
3647 {
3643 - case 0:
3644 - intelamt.microlms = 'DISABLED'
3645 - break;
3646 - case 1:
3647 - intelamt.microlms = 'CONNECTING'
3648 - break;
3649 - case 2:
3650 - intelamt.microlms = 'CONNECTED'
3651 - break;
3652 - default:
3653 - intelamt.microlms = 'unknown'
3654 - break;
3648 + case 0: intelamt.microlms = 'DISABLED'; break;
3649 + case 1: intelamt.microlms = 'CONNECTING'; break;
3650 + case 2: intelamt.microlms = 'CONNECTED'; break;
3651 + default: intelamt.microlms = 'unknown'; break;
3652 }
3653 }
3654 var p = false;
agents/modules_meshcore/apfclient.js
+12 -4
@@ -7,6 +7,8 @@
7 */
8
9 function CreateAPFClient(parent, args) {
10 + if ((args.clientuuid == null) || (args.clientuuid.length != 36)) return null; // Require a UUID if this exact length
11 +
12 var obj = {};
13 obj.parent = parent;
14 obj.args = args;
@@ -57,7 +59,7 @@ function CreateAPFClient(parent, args) {
59
60 // Intel AMT forwarded port list for non-TLS mode
61 //var pfwd_ports = [16992, 623, 16994, 5900];
60 - var pfwd_ports = [ 16992 ];
62 + var pfwd_ports = [ 16992, 16993 ];
63
64 // protocol definitions
65 var APFProtocol = {
@@ -81,7 +83,8 @@ function CreateAPFClient(parent, args) {
83 KEEPALIVE_REQUEST: 208,
84 KEEPALIVE_REPLY: 209,
85 KEEPALIVE_OPTIONS_REQUEST: 210,
84 - KEEPALIVE_OPTIONS_REPLY: 211
86 + KEEPALIVE_OPTIONS_REPLY: 211,
87 + MESH_CONNECTION_TYPE: 250 // This is a Mesh specific command that instructs the server of the connection type: 1 = Relay, 2 = LMS.
88 }
89
90 var APFDisconnectCode = {
@@ -160,13 +163,18 @@ function CreateAPFClient(parent, args) {
163 });
164
165 obj.state = CIRASTATE.INITIAL;
166 + if (typeof obj.args.conntype == 'number') { SendConnectionType(obj.forwardClient.ws, obj.args.conntype); }
167 SendProtocolVersion(obj.forwardClient.ws, obj.args.clientuuid);
168 SendServiceRequest(obj.forwardClient.ws, 'auth@amt.intel.com');
169 }
170
171 + function SendConnectionType(socket, type) {
172 + socket.write(String.fromCharCode(APFProtocol.MESH_CONNECTION_TYPE) + IntToStr(type));
173 + Debug("APF: Send connection type " + type);
174 + }
175 +
176 function SendProtocolVersion(socket, uuid) {
168 - var buuid = strToGuid(uuid);
169 - var data = String.fromCharCode(APFProtocol.PROTOCOLVERSION) + '' + IntToStr(1) + IntToStr(0) + IntToStr(0) + hex2rstr(buuid) + binzerostring(64);
177 + var data = String.fromCharCode(APFProtocol.PROTOCOLVERSION) + IntToStr(1) + IntToStr(0) + IntToStr(0) + hex2rstr(strToGuid(uuid)) + binzerostring(64);
178 socket.write(data);
179 Debug("APF: Send protocol version 1 0 " + uuid);
180 obj.cirastate = CIRASTATE.PROTOCOL_VERSION_SENT;
amt/amt-redir-mesh.js
+2 -3
@@ -113,11 +113,10 @@ module.exports.CreateAmtRedirect = function (module, domain, user, webserver, me
113 */
114
115 // If Intel AMT CIRA connection is available, use it
116 - if (((conn & 2) != 0) && (meshcentral.mpsserver.ciraConnections[nodeid] != null)) {
116 + var ciraconn = meshcentral.mpsserver.GetConnectionToNode(nodeid, null, true); // Request an OOB connection
117 + if (ciraconn != null) {
118 Debug(1, 'Opening Intel AMT CIRA transport connection to ' + nodeid + '.');
119
119 - var ciraconn = meshcentral.mpsserver.ciraConnections[nodeid];
120 -
120 // Compute target port, look at the CIRA port mappings, if non-TLS is allowed, use that, if not use TLS
121 var port = 16995;
122 if (ciraconn.tag.boundPorts.indexOf(16994) >= 0) port = 16994; // RELEASE: Always use non-TLS mode if available within CIRA
amt/amt-wsman-comm.js
+9 -9
@@ -5,7 +5,7 @@
5 */
6
7 // Construct a MeshServer object
8 -var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, transportServer) {
8 +var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, ciraConnection) {
9 //console.log('CreateWsmanComm', host, port, user, pass, tls, tlsoptions);
10
11 var obj = {};
@@ -38,7 +38,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, transpo
38 obj.pass = pass;
39 obj.xtls = tls;
40 obj.xtlsoptions = tlsoptions;
41 - obj.transportServer = transportServer; // This can be a CIRA or APF server, if null, local sockets are used as transport.
41 + obj.ciraConnection = ciraConnection; // This can be a CIRA or APF server, if null, local sockets are used as transport.
42 obj.xtlsFingerprint;
43 obj.xtlsCertificate = null;
44 obj.xtlsCheck = 0; // 0 = No TLS, 1 = CA Checked, 2 = Pinned, 3 = Untrusted
@@ -166,9 +166,9 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, transpo
166 obj.socketState = 1;
167 obj.kerberosDone = 0;
168
169 - if (obj.transportServer != null) {
170 - // Setup a new channel using the transport server (CIRA or APF)
171 - obj.socket = obj.transportServer.SetupChannelToNode(obj.host, obj.port);
169 + if (obj.ciraConnection != null) {
170 + // Setup a new channel using the CIRA/Relay/LMS connection
171 + obj.socket = obj.ciraConnection.SetupChannel(obj.port);
172 if (obj.socket == null) {
173 try { obj.xxOnSocketClosed(); } catch (e) { }
174 } else {
@@ -229,7 +229,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, transpo
229 obj.xxOnSocketConnected = function () {
230 if (obj.socket == null) return;
231 // check TLS certificate for webrelay and direct only
232 - if ((obj.transportServer == null) && (obj.xtls == 1)) {
232 + if ((obj.ciraConnection == null) && (obj.xtls == 1)) {
233 obj.xtlsCertificate = obj.socket.getPeerCertificate();
234
235 // ###BEGIN###{Certificates}
@@ -348,7 +348,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, transpo
348 if (isNaN(s)) s = 500;
349 if (s == 401 && ++(obj.authcounter) < 3) {
350 obj.challengeParams = obj.parseDigest(header['www-authenticate']); // Set the digest parameters, after this, the socket will close and we will auto-retry
351 - if (obj.transportServer == null) { obj.socket.end(); } else { obj.socket.close(); }
351 + if (obj.ciraConnection == null) { obj.socket.end(); } else { obj.socket.close(); }
352 } else {
353 var r = obj.pendingAjaxCall.shift();
354 if (r == null || r.length < 1) { console.log("pendingAjaxCall error, " + r); return; }
@@ -365,7 +365,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, transpo
365 //obj.Debug("xxOnSocketClosed");
366 obj.socketState = 0;
367 if (obj.socket != null) {
368 - if (obj.transportServer == null) { obj.socket.destroy(); } else { obj.socket.close(); }
368 + if (obj.ciraConnection == null) { obj.socket.destroy(); } else { obj.socket.close(); }
369 obj.socket = null;
370 }
371 if (obj.pendingAjaxCall.length > 0) {
@@ -376,7 +376,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, transpo
376
377 obj.xxOnSocketTimeout = function () {
378 if (obj.socket != null) {
379 - if (obj.transportServer == null) { obj.socket.destroy(); } else { obj.socket.close(); }
379 + if (obj.ciraConnection == null) { obj.socket.destroy(); } else { obj.socket.close(); }
380 obj.socket = null;
381 }
382 }
amtmanager.js
+104 -64
@@ -41,67 +41,72 @@ module.exports.CreateAmtManager = function(parent) {
41 // Handle server events
42 // TODO: Only manage devices with connections to this server. In a multi-server setup, we don't want multiple managers talking to the same device.
43 obj.HandleEvent = function (source, event, ids, id) {
44 - // React to nodes connecting and disconnecting
45 - if (event.action == 'nodeconnect') {
46 - if ((event.conn & 14) != 0) { // connectType: Bitmask, 1 = MeshAgent, 2 = Intel AMT CIRA, 4 = Intel AMT local, 8 = Intel AMT Relay, 16 = MQTT
47 - //if ((event.conn & 2) == 0) return // Debug: Only look at CIRA connections
48 -
49 - // We have an OOB connection to Intel AMT, update our information
50 - var dev = obj.amtDevices[event.nodeid];
51 - if (dev == null) { obj.amtDevices[event.nodeid] = dev = { conn: event.conn }; fetchIntelAmtInformation(event.nodeid); } else { dev.conn = event.conn; }
52 - /*
53 - } else if (((event.conn & 1) != 0) && (parent.webserver != null)) {
54 - // We have an agent connection without OOB, check if this agent supports Intel AMT
55 - var agent = parent.webserver.wsagents[event.nodeid];
56 - if ((agent == null) || (agent.agentInfo == null) || (parent.meshAgentsArchitectureNumbers[agent.agentInfo.agentId].amt == false)) { removeDevice(event.nodeid); return; }
44 + switch (event.action) {
45 + case 'nodeconnect': { // React to nodes connecting and disconnecting
46 + // See if we have an existing device we manage
47 var dev = obj.amtDevices[event.nodeid];
58 - if (dev == null) { obj.amtDevices[event.nodeid] = dev = { conn: event.conn }; fetchIntelAmtInformation(event.nodeid); } else { dev.conn = event.conn; }
59 - */
60 - } else {
61 - removeDevice(event.nodeid);
62 - }
63 - }
64 -
65 - // React to node being removed
66 - if (event.action == 'removenode') { removeDevice(event.nodeid); }
67 -
68 - // React to node wakeup command, perform Intel AMT wake if possible
69 - if ((event.action == 'wakedevices') && (Array.isArray(event.nodeids))) {
70 - for (var i in event.nodeids) { performPowerAction(event.nodeids[i], 2); }
71 - }
72 -
73 - // React to changes in a node
74 - if (event.action == 'changenode') {
75 - if (event.amtchange === 1) {
76 - // A change occured in the Intel AMT credentials, we need to reset the connection
77 - removeDevice(event.nodeid);
48
79 - // Check if the agent is connected
80 - var constate = parent.GetConnectivityState(event.nodeid);
81 - if (constate == null) return; // No OOB connectivity, exit now.
49 + // If the connection type we are using is not longer valid, remove our managed device.
50 + if ((dev != null) && (dev.conntype != null) && ((dev.conntype & event.conn) == 0)) { removeDevice(event.nodeid); dev = null; }
51
83 - if ((constate & 14) != 0) { // connectType: Bitmask, 1 = MeshAgent, 2 = Intel AMT CIRA, 4 = Intel AMT local, 8 = Intel AMT Relay, 16 = MQTT
52 + // Create or update a managed device
53 + if ((event.conn & 14) != 0) { // connectType: Bitmask, 1 = MeshAgent, 2 = Intel AMT CIRA, 4 = Intel AMT local, 8 = Intel AMT Relay, 16 = MQTT
54 // We have an OOB connection to Intel AMT, update our information
85 - var dev = obj.amtDevices[event.nodeid];
86 - if (dev == null) { obj.amtDevices[event.nodeid] = dev = { conn: constate }; fetchIntelAmtInformation(event.nodeid); } else { dev.conn = constate; }
55 + if (dev == null) {
56 + obj.amtDevices[event.nodeid] = dev = { conn: event.conn }; fetchIntelAmtInformation(event.nodeid);
57 + } else {
58 + dev.conn = event.conn;
59 + }
60 } else if (((event.conn & 1) != 0) && (parent.webserver != null)) {
88 - // We have an agent connection without OOB, check if this agent supports Intel AMT
61 + // We have an agent connection without CIRA/Local/Relay, check if this agent supports Intel AMT
62 var agent = parent.webserver.wsagents[event.nodeid];
90 - if ((agent == null) || (agent.agentInfo == null) || (parent.meshAgentsArchitectureNumbers[agent.agentInfo.agentId].amt == false)) { removeDevice(event.nodeid); return; }
91 - var dev = obj.amtDevices[event.nodeid];
92 - if (dev == null) { obj.amtDevices[event.nodeid] = dev = { conn: constate }; fetchIntelAmtInformation(event.nodeid); } else { dev.conn = constate; }
63 + if ((agent != null) && (agent.agentInfo != null) && (parent.meshAgentsArchitectureNumbers[agent.agentInfo.agentId].amt == true)) {
64 + // We could turn on LMS relay at this point.
65 + }
66 }
94 - } else {
95 - var dev = obj.amtDevices[event.nodeid];
96 - if (dev != null) {
97 - var amtchange = 0;
98 - if (dev.name != event.node.name) { dev.name = event.node.name; }
99 - if (dev.host != event.node.host) {
100 - dev.host = event.node.host;
101 - // The host has changed, if we are connected to this device locally, we need to reset.
102 - if ((dev.conn & 4) != 0) { removeDevice(dev.nodeid); return; } // We are going to wait for the AMT scanned to find this device again.
67 + break;
68 + }
69 + case 'removenode': { // React to node being removed
70 + removeDevice(event.nodeid);
71 + break;
72 + }
73 + case 'wakedevices': { // React to node wakeup command, perform Intel AMT wake if possible
74 + if (Array.isArray(event.nodeids)) { for (var i in event.nodeids) { performPowerAction(event.nodeids[i], 2); } }
75 + break;
76 + }
77 + case 'changenode': { // React to changes in a node
78 + if (event.amtchange === 1) {
79 + // A change occured in the Intel AMT credentials, we need to reset the connection
80 + removeDevice(event.nodeid);
81 +
82 + // Check if the agent is connected
83 + var constate = parent.GetConnectivityState(event.nodeid);
84 + if (constate == null) return; // No OOB connectivity, exit now.
85 +
86 + if ((constate & 14) != 0) { // connectType: Bitmask, 1 = MeshAgent, 2 = Intel AMT CIRA, 4 = Intel AMT local, 8 = Intel AMT Relay, 16 = MQTT
87 + // We have an OOB connection to Intel AMT, update our information
88 + var dev = obj.amtDevices[event.nodeid];
89 + if (dev == null) { obj.amtDevices[event.nodeid] = dev = { conn: constate }; fetchIntelAmtInformation(event.nodeid); } else { dev.conn = constate; }
90 + } else if (((event.conn & 1) != 0) && (parent.webserver != null)) {
91 + // We have an agent connection without OOB, check if this agent supports Intel AMT
92 + var agent = parent.webserver.wsagents[event.nodeid];
93 + if ((agent == null) || (agent.agentInfo == null) || (parent.meshAgentsArchitectureNumbers[agent.agentInfo.agentId].amt == false)) { removeDevice(event.nodeid); return; }
94 + var dev = obj.amtDevices[event.nodeid];
95 + if (dev == null) { obj.amtDevices[event.nodeid] = dev = { conn: constate }; fetchIntelAmtInformation(event.nodeid); } else { dev.conn = constate; }
96 + }
97 + } else {
98 + var dev = obj.amtDevices[event.nodeid];
99 + if (dev != null) {
100 + var amtchange = 0;
101 + if (dev.name != event.node.name) { dev.name = event.node.name; }
102 + if (dev.host != event.node.host) {
103 + dev.host = event.node.host;
104 + // The host has changed, if we are connected to this device locally, we need to reset.
105 + if ((dev.conn & 4) != 0) { removeDevice(dev.nodeid); return; } // We are going to wait for the AMT scanned to find this device again.
106 + }
107 }
108 }
109 + break;
110 }
111 }
112 }
@@ -186,23 +191,24 @@ module.exports.CreateAmtManager = function(parent) {
191 if (node.host) { dev.host = node.host.toLowerCase(); }
192 dev.meshid = node.meshid;
193 dev.intelamt = node.intelamt;
189 - attemptInitialContact(nodeid, dev);
194 + attemptInitialContact(dev);
195 });
196 }
197
198 // Attempt to perform initial contact with Intel AMT
194 - function attemptInitialContact(nodeid, dev) {
195 - if (dev == null) { dev = obj.amtDevices[nodeid]; }
199 + function attemptInitialContact(dev) {
200 if (dev == null) return;
201 + //console.log('attemptInitialContact', dev.name);
202
203 if ((dev.acctry == null) && ((typeof dev.intelamt.user != 'string') || (typeof dev.intelamt.pass != 'string'))) {
204 if (obj.amtAdminAccounts.length > 0) { dev.acctry = 0; } else { return; }
205 }
206
207 // Handle the case where the Intel AMT CIRA is connected (conn & 2)
208 + // In this connection type, we look at the port bindings to see if we need to do TLS or not.
209 if ((dev.conn & 2) != 0) {
210 // Check to see if CIRA is connected on this server.
205 - var ciraconn = parent.mpsserver.ciraConnections[dev.nodeid];
211 + var ciraconn = parent.mpsserver.GetConnectionToNode(dev.nodeid, null, 0); // Select the CIRA connection
212 if ((ciraconn == null) || (ciraconn.tag == null) || (ciraconn.tag.boundPorts == null)) { removeDevice(dev.nodeid); return; } // CIRA connection is not on this server, no need to deal with this device anymore.
213
214 // See what user/pass to try.
@@ -218,11 +224,12 @@ module.exports.CreateAmtManager = function(parent) {
224 // Connect now
225 //console.log('CIRA-Connect', (dotls == 1)?"TLS":"NoTLS", dev.name, dev.host, user, pass);
226 var comm;
227 + dotls = 0; // TODO: We don't support TLS with CIRA/Relay/LMS connections yet. Remove this when we do.
228 if (dotls == 1) {
222 - comm = CreateWsmanComm(dev.nodeid, 16993, user, pass, 1, null, parent.mpsserver); // Perform TLS
229 + comm = CreateWsmanComm(dev.nodeid, 16993, user, pass, 1, null, ciraconn); // Perform TLS
230 comm.xtlsFingerprint = 0; // Perform no certificate checking
231 } else {
225 - comm = CreateWsmanComm(dev.nodeid, 16992, user, pass, 0, null, parent.mpsserver); // No TLS
232 + comm = CreateWsmanComm(dev.nodeid, 16992, user, pass, 0, null, ciraconn); // No TLS
233 }
234 var wsstack = WsmanStackCreateService(comm);
235 dev.amtstack = AmtStackCreateService(wsstack);
@@ -234,12 +241,45 @@ module.exports.CreateAmtManager = function(parent) {
241 return; // If CIRA is connected, don't try any other methods.
242 }
243
244 + // Handle the case where the Intel AMT relay is connected (conn & 8)
245 + if ((dev.conn & 8) != 0) {
246 + // Check to see if CIRA is connected on this server.
247 + var ciraconn = parent.mpsserver.GetConnectionToNode(dev.nodeid, null, 1); // Select a relay connection
248 + if ((ciraconn == null) || (ciraconn.tag == null) || (ciraconn.tag.boundPorts == null)) { removeDevice(dev.nodeid); return; } // CIRA connection is not on this server, no need to deal with this device anymore.
249 +
250 + // See what user/pass to try.
251 + var user = null, pass = null;
252 + if (dev.acctry == null) { user = dev.intelamt.user; pass = dev.intelamt.pass; } else { user = obj.amtAdminAccounts[dev.acctry].user; pass = obj.amtAdminAccounts[dev.acctry].pass; }
253 +
254 + // Connect now
255 + var comm;
256 + dev.tlsfail = true; // TODO: We don't support TLS with CIRA/Relay/LMS connections yet. Remove this when we do.
257 + if (dev.tlsfail !== true) {
258 + //console.log('Relay-Connect', "TLS", dev.name, dev.host, user, pass);
259 + comm = CreateWsmanComm(dev.nodeid, 16993, user, pass, 1, null, ciraconn); // Perform TLS
260 + comm.xtlsFingerprint = 0; // Perform no certificate checking
261 + } else {
262 + //console.log('Relay-Connect', "NoTLS", dev.name, dev.host, user, pass);
263 + comm = CreateWsmanComm(dev.nodeid, 16992, user, pass, 0, null, ciraconn); // No TLS
264 + }
265 + var wsstack = WsmanStackCreateService(comm);
266 + dev.amtstack = AmtStackCreateService(wsstack);
267 + dev.amtstack.dev = dev;
268 + obj.activeLocalConnections[dev.host] = dev;
269 + dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], attemptLocalConnectResponse);
270 + dev.conntype = 8; // Relay
271 +
272 + return; // If relay is connected, don't try any other methods.
273 + }
274 +
275 // Handle the case where the Intel AMT local scanner found the device (conn & 4)
276 if (((dev.conn & 4) != 0) && (typeof dev.host == 'string')) {
277 // Since we don't allow two or more connections to the same host, check if a pending connection is active.
278 if (obj.activeLocalConnections[dev.host] != null) {
279 // Active connection, hold and try later.
242 - setTimeout(function () { attemptInitialContact(nodeid); }, 5000);
280 + var tryAgainFunc = function tryAgainFunc() { if (obj.amtDevices[tryAgainFunc.dev.nodeid] != null) { attemptInitialContact(tryAgainFunc.dev); } }
281 + tryAgainFunc.dev = dev;
282 + setTimeout(tryAgainFunc, 5000);
283 } else {
284 // No active connections, see what user/pass to try.
285 var user = null, pass = null;
@@ -248,11 +288,11 @@ module.exports.CreateAmtManager = function(parent) {
288 // Connect now
289 var comm;
290 if (dev.tlsfail !== true) {
251 - //console.log('Connect', "TLS", dev.name, dev.host, user, pass);
291 + //console.log('Direct-Connect', "TLS", dev.name, dev.host, user, pass);
292 comm = CreateWsmanComm(dev.host, 16993, user, pass, 1); // Always try with TLS first
293 comm.xtlsFingerprint = 0; // Perform no certificate checking
294 } else {
255 - //console.log('Connect', "NoTLS", dev.name, dev.host, user, pass);
295 + //console.log('Direct-Connect', "NoTLS", dev.name, dev.host, user, pass);
296 comm = CreateWsmanComm(dev.host, 16992, user, pass, 0); // Try without TLS
297 }
298 var wsstack = WsmanStackCreateService(comm);
@@ -301,11 +341,11 @@ module.exports.CreateAmtManager = function(parent) {
341 // We got a bad response
342 if ((dev.conntype == 1) && (dev.tlsfail !== true) && (status == 408)) {
343 // TLS error on a local connection, try again without TLS
304 - dev.tlsfail = true; attemptInitialContact(dev.nodeid, dev); return;
344 + dev.tlsfail = true; attemptInitialContact(dev); return;
345 } else if (status == 401) {
346 // Authentication error, see if we can use alternative credentials
307 - if ((dev.acctry == null) && (obj.amtAdminAccounts.length > 0)) { dev.acctry = 0; attemptInitialContact(dev.nodeid, dev); return; }
308 - if ((dev.acctry != null) && (obj.amtAdminAccounts.length > (dev.acctry + 1))) { dev.acctry++; attemptInitialContact(dev.nodeid, dev); return; }
347 + if ((dev.acctry == null) && (obj.amtAdminAccounts.length > 0)) { dev.acctry = 0; attemptInitialContact(dev); return; }
348 + if ((dev.acctry != null) && (obj.amtAdminAccounts.length > (dev.acctry + 1))) { dev.acctry++; attemptInitialContact(dev); return; }
349
350 // We are unable to authenticate to this device, clear Intel AMT credentials.
351 ClearDeviceCredentials(dev);
amtscanner.js
+2 -2
@@ -164,8 +164,8 @@ module.exports.CreateAmtScanner = function (parent) {
164 if (err == null && docs.length > 0) {
165 for (var i in docs) {
166 var doc = docs[i], host = doc.host.toLowerCase();
167 - const ciraConnection = obj.parent.mpsserver ? obj.parent.mpsserver.ciraConnections[doc._id] : null;
168 - if ((host != '127.0.0.1') && (host != '::1') && (host.toLowerCase() != 'localhost') && (ciraConnection == null)) {
167 + const ciraConnections = obj.parent.mpsserver ? obj.parent.mpsserver.GetConnectionToNode(doc._id, null, true) : null; // See if any OOB connections are present
168 + if ((host != '127.0.0.1') && (host != '::1') && (host.toLowerCase() != 'localhost') && (ciraConnections == null)) {
169 var scaninfo = obj.scanTable[doc._id];
170 if (scaninfo == undefined) {
171 var tag = obj.nextTag++;
meshagent.js
+1 -1
@@ -79,7 +79,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
79 const state = parent.parent.GetConnectivityState(obj.dbNodeKey);
80 if ((state != null) && (state.connectivity != null)) {
81 if ((state.connectivity & 1) != 0) { parent.wsagents[obj.dbNodeKey].close(); } // Disconnect mesh agent
82 - if ((state.connectivity & 2) != 0) { parent.parent.mpsserver.close(parent.parent.mpsserver.ciraConnections[obj.dbNodeKey]); } // Disconnect CIRA connection
82 + if ((state.connectivity & 2) != 0) { parent.parent.mpsserver.closeAllForNode(obj.dbNodeKey); } // Disconnect CIRA connection
83 }
84 } else {
85 // Update the last connect time
meshcentral.js
+4 -1
@@ -1422,7 +1422,10 @@ function CreateMeshCentralServer(config, args) {
1422 rs: obj.webserver.relaySessionCount
1423 }
1424 };
1425 - if (obj.mpsserver != null) { data.conn.am = Object.keys(obj.mpsserver.ciraConnections).length; }
1425 + if (obj.mpsserver != null) {
1426 + data.conn.am = 0;
1427 + for (var i in obj.mpsserver.ciraConnections) { data.conn.am += obj.mpsserver.ciraConnections[i].length; }
1428 + }
1429 if (obj.firstStats === true) { delete obj.firstStats; data.first = true; }
1430 obj.db.SetServerStats(data); // Save the stats to the database
1431 obj.DispatchEvent(['*'], obj, { action: 'servertimelinestats', data: data }); // Event the server stats
meshuser.js
+26 -4
@@ -406,7 +406,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
406 RelayCount: Object.keys(parent.wsrelays).length
407 };
408 if (parent.relaySessionErrorCount != 0) { serverStats.RelayErrors = parent.relaySessionErrorCount; }
409 - if (parent.parent.mpsserver != null) { serverStats.ConnectedIntelAMT = Object.keys(parent.parent.mpsserver.ciraConnections).length; }
409 + if (parent.parent.mpsserver != null) {
410 + serverStats.ConnectedIntelAMT = 0;
411 + for (var i in parent.parent.mpsserver.ciraConnections) { serverStats.ConnectedIntelAMT += parent.parent.mpsserver.ciraConnections[i].length; }
412 + }
413
414 // Take a look at agent errors
415 var agentstats = parent.getAgentStats();
@@ -657,7 +660,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
660 docs[i].conn = state.connectivity;
661 docs[i].pwr = state.powerState;
662 if ((state.connectivity & 1) != 0) { var agent = parent.wsagents[docs[i]._id]; if (agent != null) { docs[i].agct = agent.connectTime; } }
660 - if ((state.connectivity & 2) != 0) { var cira = parent.parent.mpsserver.ciraConnections[docs[i]._id]; if (cira != null) { docs[i].cict = cira.tag.connectTime; } }
663 +
664 + // Use the connection time of the CIRA/Relay connection
665 + if ((state.connectivity & 2) != 0) { var cira = parent.parent.mpsserver.GetConnectionToNode(docs[i]._id, null, true); if (cira != null) { docs[i].cict = cira[0].tag.connectTime; } }
666 }
667
668 // Compress the meshid's
@@ -1062,6 +1067,21 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1067 }
1068 break;
1069 }
1070 + case 'mps': { // List all MPS connections and types.
1071 + if (parent.parent.mpsserver == null) {
1072 + r = 'MPS not enabled.';
1073 + } else {
1074 + const connectionTypes = ['CIRA', 'Relay', 'LMS'];
1075 + for (var nodeid in parent.parent.mpsserver.ciraConnections) {
1076 + r += nodeid;
1077 + var connections = parent.parent.mpsserver.ciraConnections[nodeid];
1078 + for (var i in connections) { r += ', ' + connectionTypes[connections[i].tag.connType]; }
1079 + r += '\r\n';
1080 + }
1081 + if (r == '') { r = 'MPS has not connections.'; }
1082 + }
1083 + break;
1084 + }
1085 case 'dbstats': {
1086 parent.parent.db.getStats(function (stats) {
1087 var r2 = '';
@@ -3458,7 +3478,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3478 node.conn = state.connectivity;
3479 node.pwr = state.powerState;
3480 if ((state.connectivity & 1) != 0) { var agent = parent.wsagents[node._id]; if (agent != null) { node.agct = agent.connectTime; } }
3461 - if ((state.connectivity & 2) != 0) { var cira = parent.parent.mpsserver.ciraConnections[node._id]; if (cira != null) { node.cict = cira.tag.connectTime; } }
3481 +
3482 + // Uuse the connection time of the CIRA/Relay connection
3483 + if ((state.connectivity & 2) != 0) { var cira = parent.parent.mpsserver.GetConnectionToNode(node._id, null, true); if (cira != null) { node.cict = cira[0].tag.connectTime; } }
3484 }
3485
3486 // Event the node change
@@ -3527,7 +3549,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3549 var state = parent.parent.GetConnectivityState(nodeid);
3550 if ((state != null) && (state.connectivity != null)) {
3551 if ((state.connectivity & 1) != 0) { parent.wsagents[nodeid].close(); } // Disconnect mesh agent
3530 - if ((state.connectivity & 2) != 0) { parent.parent.mpsserver.close(parent.parent.mpsserver.ciraConnections[nodeid]); } // Disconnect CIRA connection
3552 + if ((state.connectivity & 2) != 0) { parent.parent.mpsserver.closeAllForNode(nodeid); } // Disconnect CIRA/Relay/LMS connections
3553 }
3554 });
3555 }
mpsserver.js
+127 -43
@@ -22,7 +22,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
22 obj.db = db;
23 obj.args = args;
24 obj.certificates = certificates;
25 - obj.ciraConnections = {}; // NodeID --> Socket
25 + obj.ciraConnections = {}; // NodeID --> [ Socket ]
26 var tlsSessionStore = {}; // Store TLS session information for quick resume.
27 var tlsSessionStoreCount = 0; // Number of cached TLS session information in store.
28 const constants = (require('crypto').constants ? require('crypto').constants : require('constants')); // require('constants') is deprecated in Node 11.10, use require('crypto').constants instead.
@@ -79,7 +79,8 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
79 KEEPALIVE_REQUEST: 208,
80 KEEPALIVE_REPLY: 209,
81 KEEPALIVE_OPTIONS_REQUEST: 210,
82 - KEEPALIVE_OPTIONS_REPLY: 211
82 + KEEPALIVE_OPTIONS_REPLY: 211,
83 + MESH_CONNECTION_TYPE: 250 // This is a Mesh specific command that instructs the server of the connection type: 1 = Relay, 2 = LMS.
84 };
85
86 /*
@@ -142,22 +143,71 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
143 var socketErrorCount = 0;
144 var maxDomainDevicesReached = 0;
145
145 - // Delay setting the connectivity state by 300ms to allow time for CIRA port mappings to be established
146 - // Report power state as "present" (7) until Intel AMT manager starts polling for power state.
147 - function delayedSetConnectivityState(meshid, nodeid, connectTime, connType) {
148 - if (nodeid.startsWith('*')) return; // Don't set connectivity state for Intel AMT self agent relay
149 - var f = function setConnFunc() { if (obj.ciraConnections[setConnFunc.nodeid] != null) { obj.parent.SetConnectivityState(setConnFunc.meshid, setConnFunc.nodeid, setConnFunc.connectTime, setConnFunc.connType, 7); } }
150 - f.nodeid = nodeid;
151 - f.meshid = meshid;
152 - f.connectTime = connectTime;
153 - f.connType = connType;
146 + // Add a CIRA connection to the connection list
147 + function addCiraConnection(socket) {
148 + // Check if there is already a connection of the same type
149 + var sameType = false, connections = obj.ciraConnections[socket.tag.nodeid];
150 + if (connections != null) { for (var i in connections) { var conn = connections[i]; if (conn.tag.connType === socket.tag.connType) { sameType = true; } } }
151 +
152 + // Add this connection to the connections list
153 + if (connections == null) { obj.ciraConnections[socket.tag.nodeid] = [socket]; } else { obj.ciraConnections[socket.tag.nodeid].push(socket); }
154 + if ((socket.tag.connType != 0) && (socket.tag.connType != 1)) return; // If not a CIRA or Relay connection, we don't indicate a connection state change
155 +
156 + // Update connectivity state
157 + // Report the new state of a CIRA/Relay/LMS connection after a short delay. This is to wait for the connection to have the bounded ports setup before we advertise this new connection.
158 + socket.xxStartHold = 1;
159 + var f = function setConnFunc() {
160 + delete setConnFunc.socket.xxStartHold;
161 + const ciraArray = obj.ciraConnections[setConnFunc.socket.tag.nodeid];
162 + if ((ciraArray != null) && ((ciraArray.indexOf(setConnFunc.socket) >= 0))) { // Check if this connection is still present
163 + if (setConnFunc.socket.tag.connType == 0) {
164 + // Intel AMT CIRA connection. This connection indicates the remote device is present.
165 + obj.parent.SetConnectivityState(setConnFunc.socket.tag.meshid, setConnFunc.socket.tag.nodeid, setConnFunc.socket.tag.connectTime, 2, 7); // 7 = Present
166 + } else if (setConnFunc.socket.tag.connType == 1) {
167 + // Intel AMT Relay connection. This connection does not give any information about the remote device's power state.
168 + obj.parent.SetConnectivityState(setConnFunc.socket.tag.meshid, setConnFunc.socket.tag.nodeid, setConnFunc.socket.tag.connectTime, 8, 0); // 0 = Unknown
169 + } else if (setConnFunc.socket.tag.connType == 2) {
170 + // Intel AMT LMS connection. We don't notify of these connections except telling the Intel AMT manager about them.
171 + // TODO: Notify AMT manager
172 + }
173 + }
174 + }
175 + f.socket = socket;
176 setTimeout(f, 300);
177 }
178
179 + // Remove a CIRA connection from the connection list
180 + function removeCiraConnection(socket) {
181 + // Remove the connection from the list if present.
182 + const ciraArray = obj.ciraConnections[socket.tag.nodeid];
183 + if (ciraArray == null) return;
184 + var i = ciraArray.indexOf(socket);
185 + if (i == -1) return;
186 + ciraArray.splice(i, 1);
187 + if (ciraArray.length == 0) { delete obj.ciraConnections[socket.tag.nodeid]; } else { obj.ciraConnections[socket.tag.nodeid] = ciraArray; }
188 +
189 + // If we are removing a connection during the hold period, don't clear any state since it was never set.
190 + if (socket.xxStartHold == 1) return;
191 +
192 + // Check if there is already a connection of the same type
193 + var sameType = false, connections = obj.ciraConnections[socket.tag.nodeid];
194 + if (connections != null) { for (var i in connections) { var conn = connections[i]; if (conn.tag.connType === socket.tag.connType) { sameType = true; } } }
195 + if (sameType == true) return; // if there is a connection of the same type, don't change the connection state.
196 +
197 + // Update connectivity state
198 + if (socket.tag.connType == 0) {
199 + obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2); // CIRA
200 + } else if (socket.tag.connType == 1) {
201 + obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 8); // Relay
202 + }
203 + }
204 +
205 // Return statistics about this MPS server
206 obj.getStats = function () {
207 + var ciraConnectionCount = 0;
208 + for (var i in obj.ciraConnections) { ciraConnectionCount += obj.ciraConnections[i].length; }
209 return {
160 - ciraConnections: Object.keys(obj.ciraConnections).length,
210 + ciraConnections: ciraConnectionCount,
211 tlsSessionStore: Object.keys(tlsSessionStore).length,
212 connectionCount: connectionCount,
213 userAuthRequestCount: userAuthRequestCount,
@@ -224,8 +274,11 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
274
275 obj.onWebSocketConnection = function (socket) {
276 connectionCount++;
227 - // connType: 2 = CIRA, 8 = Relay
228 - socket.tag = { first: true, connType: 2, clientCert: null, accumulator: '', activetunnels: 0, boundPorts: [], websocket: true, socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
277 + // connType: 0 = CIRA, 1 = Relay, 2 = LMS
278 + socket.tag = { first: true, connType: 0, clientCert: null, accumulator: '', activetunnels: 0, boundPorts: [], websocket: true, socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
279 + socket.SetupChannel = function SetupChannel(targetport) { return SetupChannel.parent.SetupChannel(SetupChannel.conn, targetport); }
280 + socket.SetupChannel.parent = obj;
281 + socket.SetupChannel.conn = socket;
282 socket.websocket = 1;
283 parent.debug('mps', "New CIRA websocket connection");
284
@@ -245,8 +298,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
298 socket.addListener('close', function () {
299 socketClosedCount++;
300 parent.debug('mps', "CIRA websocket closed", this.tag.meshid, this.tag.nodeid);
248 - try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
249 - if (!this.tag.nodeid.startsWith('*')) { obj.parent.ClearConnectivityState(this.tag.meshid, this.tag.nodeid, this.tag.connType); }
301 + removeCiraConnection(socket);
302 });
303
304 socket.addListener('error', function (e) {
@@ -258,12 +310,15 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
310 // Called when a new TLS/TCP connection is accepted
311 function onConnection(socket) {
312 connectionCount++;
261 - // connType: 2 = CIRA, 8 = Relay
313 + // connType: 0 = CIRA, 1 = Relay, 2 = LMS
314 if (obj.args.mpstlsoffload) {
263 - socket.tag = { first: true, connType: 2, clientCert: null, accumulator: '', activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
315 + socket.tag = { first: true, connType: 0, clientCert: null, accumulator: '', activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
316 } else {
265 - socket.tag = { first: true, connType: 2, clientCert: socket.getPeerCertificate(true), accumulator: '', activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
317 + socket.tag = { first: true, connType: 0, clientCert: socket.getPeerCertificate(true), accumulator: '', activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
318 }
319 + socket.SetupChannel = function SetupChannel(targetport) { return SetupChannel.parent.SetupChannel(SetupChannel.conn, targetport); }
320 + socket.SetupChannel.parent = obj;
321 + socket.SetupChannel.conn = socket;
322 socket.setEncoding('binary');
323 parent.debug('mps', "New CIRA connection");
324
@@ -274,8 +329,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
329 socket.addListener('close', function () {
330 socketClosedCount++;
331 parent.debug('mps', 'CIRA connection closed');
277 - try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
278 - obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connType);
332 + removeCiraConnection(socket);
333 });
334
335 socket.addListener('error', function (e) {
@@ -382,8 +436,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
436 obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: parent.webserver.CloneSafeNode(device), msg: change, domain: domainid });
437
438 // Add the connection to the MPS connection list
385 - obj.ciraConnections[socket.tag.nodeid] = socket;
386 - delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, socket.tag.connType);
439 + addCiraConnection(socket);
440 }
441 });
442 return;
@@ -412,8 +465,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
465 }
466
467 // Add the connection to the MPS connection list
415 - obj.ciraConnections[socket.tag.nodeid] = socket;
416 - delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, socket.tag.connType);
468 + addCiraConnection(socket);
469 });
470 } else {
471 // This node connected without certificate authentication, use password auth
@@ -521,8 +573,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
573 obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: parent.webserver.CloneSafeNode(device), msg: change, domain: mesh.domain });
574
575 // Add the connection to the MPS connection list
524 - obj.ciraConnections[socket.tag.nodeid] = socket;
525 - delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, socket.tag.connType);
576 + addCiraConnection(socket);
577 SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
578 }
579 });
@@ -545,8 +596,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
596 }
597
598 // Add the connection to the MPS connection list
548 - obj.ciraConnections[socket.tag.nodeid] = socket;
549 - delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, socket.tag.connType);
599 + addCiraConnection(socket);
600 SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
601 });
602 } else if (mesh.mtype == 2) { // If this is a agent mesh, search the mesh for this device UUID
@@ -584,8 +634,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
634 socket.tag.connectTime = Date.now();
635
636 // Add the connection to the MPS connection list
587 - obj.ciraConnections[socket.tag.nodeid] = socket;
588 - delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, socket.tag.connType);
637 + addCiraConnection(socket);
638 SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
639 });
640 } else { // Unknown mesh type
@@ -818,10 +867,17 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
867 var ReasonCode = common.ReadInt(data, 1);
868 disconnectCommandCount++;
869 parent.debug('mpscmd', '--> DISCONNECT', ReasonCode);
821 - try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
822 - obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connType);
870 + removeCiraConnection(socket);
871 return 7;
872 }
873 + case APFProtocol.MESH_CONNECTION_TYPE: // This is a Mesh specific command to indicate the connect type.
874 + {
875 + if (len < 5) return 0;
876 + if ((socket.tag.connType == 0) && (socket.tag.SystemId == null)) { // Once set, the connection type can't be changed.
877 + socket.tag.connType = common.ReadInt(data, 1); // 0 = CIRA, 1 = Relay, 2 = LMS
878 + }
879 + return 5;
880 + }
881 default:
882 {
883 parent.debug('mpscmd', '--> Unknown CIRA command: ' + cmd);
@@ -833,8 +889,14 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
889 // Disconnect CIRA tunnel
890 obj.close = function (socket) {
891 try { socket.end(); } catch (e) { }
836 - try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
837 - obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connType);
892 + removeCiraConnection(socket);
893 + };
894 +
895 + // Disconnect all CIRA tunnel for a given NodeId
896 + obj.closeAllForNode = function (nodeid) {
897 + var connections = obj.ciraConnections[nodeid];
898 + if (connections == null) return;
899 + for (var i in connections) { obj.close(connections[i]); }
900 };
901
902 function SendServiceAccept(socket, service) {
@@ -926,18 +988,36 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
988 }
989 }
990
929 - // Setup a new channel to a nodeid
930 - obj.SetupChannelToNode = function (nodeid, targetport) {
931 - var ciraconn = obj.ciraConnections[nodeid];
932 - if (ciraconn == null) return null;
933 - return obj.SetupChannel(ciraconn, targetport);
991 + // Returns a CIRA/Relay/LMS connection to a nodeid, use the best possible connection, CIRA first, Relay second, LMS third.
992 + // if oob is set to true, don't allow an LMS connection.
993 + obj.GetConnectionToNode = function (nodeid, targetport, oob) {
994 + var connectionArray = obj.ciraConnections[nodeid];
995 + if (connectionArray == null) return null;
996 + var selectConn = null;
997 + // Select the best connection, which is the one with the lowest connType value.
998 + for (var i in connectionArray) {
999 + var conn = connectionArray[i];
1000 + if ((oob === true) && (conn.tag.connType == 2)) continue; // If an OOB connection is required, don't allow LMS connections.
1001 + if ((typeof oob === 'number') && (conn.tag.connType !== oob)) continue; // if OOB specifies an exact connection type, filter on this type.
1002 + if ((targetport != null) && (conn.tag.boundPorts.indexOf(targetport) == -1)) continue; // This connection does not route to the target port.
1003 + if ((selectConn == null) || (conn.tag.connType < selectConn.tag.connType)) { selectConn = conn; }
1004 + }
1005 + return selectConn;
1006 + }
1007 +
1008 + // Setup a new channel to a nodeid, use the best possible connection, CIRA first, Relay second, LMS third.
1009 + // if oob is set to true, don't allow an LMS connection.
1010 + obj.SetupChannelToNode = function (nodeid, targetport, oob) {
1011 + var conn = obj.GetConnectionToNode(nodeid, targetport, oob);
1012 + if (conn == null) return null;
1013 + return obj.SetupChannel(conn, targetport);
1014 }
1015
1016 // Setup a new channel
1017 obj.SetupChannel = function (socket, targetport) {
1018 var sourceport = (socket.tag.nextsourceport++ % 30000) + 1024;
1019 var cirachannel = { targetport: targetport, channelid: socket.tag.nextchannelid++, socket: socket, state: 1, sendcredits: 0, amtpendingcredits: 0, amtCiraWindow: 0, ciraWindow: 32768 };
940 - SendChannelOpen(socket, false, cirachannel.channelid, cirachannel.ciraWindow, socket.tag.host, targetport, "1.2.3.4", sourceport);
1020 + SendChannelOpen(socket, false, cirachannel.channelid, cirachannel.ciraWindow, socket.tag.host, targetport, '1.2.3.4', sourceport);
1021
1022 // This function writes data to this CIRA channel
1023 cirachannel.write = function (data) {
@@ -1015,8 +1095,12 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
1095
1096 // Change a node to a new meshid, this is called when a node changes groups.
1097 obj.changeDeviceMesh = function (nodeid, newMeshId) {
1018 - var socket = obj.ciraConnections[nodeid];
1019 - if ((socket != null) && (socket.tag != null)) { socket.tag.meshid = newMeshId; }
1098 + var connectionArray = obj.ciraConnections[nodeid];
1099 + if (connectionArray == null) return;
1100 + for (var i in connectionArray) {
1101 + var socket = connectionArray[i];
1102 + if ((socket != null) && (socket.tag != null)) { socket.tag.meshid = newMeshId; }
1103 + }
1104 }
1105
1106 // Called when handling incoming HTTP data
webserver.js
+3 -3
@@ -3375,11 +3375,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3375 }
3376
3377 // If Intel AMT CIRA connection is available, use it
3378 - if (((conn & 2) != 0) && (parent.mpsserver.ciraConnections[req.query.host] != null)) {
3378 + var ciraconn = parent.mpsserver.GetConnectionToNode(req.query.host, null, false);
3379 + if (ciraconn != null) {
3380 parent.debug('web', 'Opening relay CIRA channel connection to ' + req.query.host + '.');
3381
3381 - var ciraconn = parent.mpsserver.ciraConnections[req.query.host];
3382 -
3382 + // TODO: If ciraconn is a relay connection, we can't detect the TLS state like this.
3383 // Compute target port, look at the CIRA port mappings, if non-TLS is allowed, use that, if not use TLS
3384 var port = 16993;
3385 //if (node.intelamt.tls == 0) port = 16992; // DEBUG: Allow TLS flag to set TLS mode within CIRA