From 0cab70f7d4afe25698792e6da729179a16310678 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Thu, 8 Oct 2020 12:50:27 -0700 Subject: [PATCH] First version with CIRA support in AMT Manager. --- amt/amt-redir-mesh.js | 4 ++-- amt/amt-wsman-comm.js | 4 ++-- amtmanager.js | 51 +++++++++++++++++++++++++++++++++++++++---- apfserver.js | 9 ++++---- mpsserver.js | 33 +++++++++++++++++++--------- webserver.js | 4 ++-- 6 files changed, 81 insertions(+), 24 deletions(-) diff --git a/amt/amt-redir-mesh.js b/amt/amt-redir-mesh.js index 4c1a9356..5f1baf5b 100644 --- a/amt/amt-redir-mesh.js +++ b/amt/amt-redir-mesh.js @@ -126,7 +126,7 @@ module.exports.CreateAmtRedirect = function (module, domain, user, webserver, me if ((port == 16993) || (port == 16995)) { // Perform TLS - ( TODO: THIS IS BROKEN on Intel AMT v7 but works on v10, Not sure why. Well, could be broken TLS 1.0 in firmware ) var ser = new SerialTunnel(); - var chnl = meshcentral.mpsserver.SetupCiraChannel(ciraconn, port); + var chnl = meshcentral.mpsserver.SetupChannel(ciraconn, port); // let's chain up the TLSSocket <-> SerialTunnel <-> CIRA APF (chnl) // Anything that needs to be forwarded by SerialTunnel will be encapsulated by chnl write @@ -171,7 +171,7 @@ module.exports.CreateAmtRedirect = function (module, domain, user, webserver, me obj.forwardclient.xtls = 1; } else { // Without TLS - obj.forwardclient = meshcentral.mpsserver.SetupCiraChannel(ciraconn, port); + obj.forwardclient = meshcentral.mpsserver.SetupChannel(ciraconn, port); obj.forwardclient.xtls = 0; } diff --git a/amt/amt-wsman-comm.js b/amt/amt-wsman-comm.js index 317db0f0..4570489c 100644 --- a/amt/amt-wsman-comm.js +++ b/amt/amt-wsman-comm.js @@ -167,8 +167,8 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, transpo obj.kerberosDone = 0; if (obj.transportServer != null) { - // CIRA or APF server - obj.socket = obj.transportServer.SetupCiraChannelToHost(obj.host, obj.port); + // Setup a new channel using the transport server (CIRA or APF) + obj.socket = obj.transportServer.SetupChannelToNode(obj.host, obj.port); if (obj.socket == null) { try { obj.xxOnSocketClosed(); } catch (e) { } } else { diff --git a/amtmanager.js b/amtmanager.js index 0143a6d6..76a17e8f 100644 --- a/amtmanager.js +++ b/amtmanager.js @@ -44,15 +44,19 @@ module.exports.CreateAmtManager = function(parent) { // React to nodes connecting and disconnecting if (event.action == 'nodeconnect') { if ((event.conn & 14) != 0) { // connectType: Bitmask, 1 = MeshAgent, 2 = Intel AMT CIRA, 4 = Intel AMT local, 8 = Intel AMT Relay, 16 = MQTT + if ((event.conn & 2) == 0) return // Debug: Only look at CIRA connections ***************************** + // We have an OOB connection to Intel AMT, update our information var dev = obj.amtDevices[event.nodeid]; if (dev == null) { obj.amtDevices[event.nodeid] = dev = { conn: event.conn }; fetchIntelAmtInformation(event.nodeid); } else { dev.conn = event.conn; } + /* } else if (((event.conn & 1) != 0) && (parent.webserver != null)) { // We have an agent connection without OOB, check if this agent supports Intel AMT var agent = parent.webserver.wsagents[event.nodeid]; if ((agent == null) || (agent.agentInfo == null) || (parent.meshAgentsArchitectureNumbers[agent.agentInfo.agentId].amt == false)) { removeDevice(event.nodeid); return; } var dev = obj.amtDevices[event.nodeid]; if (dev == null) { obj.amtDevices[event.nodeid] = dev = { conn: event.conn }; fetchIntelAmtInformation(event.nodeid); } else { dev.conn = event.conn; } + */ } else { removeDevice(event.nodeid); } @@ -195,6 +199,42 @@ module.exports.CreateAmtManager = function(parent) { if (obj.amtAdminAccounts.length > 0) { dev.acctry = 0; } else { return; } } + // Handle the case where the Intel AMT CIRA is connected (conn & 2) + if ((dev.conn & 2) != 0) { + // Check to see if CIRA is connected on this server. + var ciraconn = parent.mpsserver.ciraConnections[dev.nodeid]; + 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. + + // See what user/pass to try. + var user = null, pass = null; + 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; } + + // See if we need to perform TLS or not. We prefer not to do TLS within CIRA. + var dotls = -1; + if (ciraconn.tag.boundPorts.indexOf('16992')) { dotls = 0; } + else if (ciraconn.tag.boundPorts.indexOf('16993')) { dotls = 1; } + if (dotls == -1) { removeDevice(dev.nodeid); return; } // The Intel AMT ports are not open, not a device we can deal with. + + // Connect now + console.log('CIRA-Connect', (dotls == 1)?"TLS":"NoTLS", dev.name, dev.host, user, pass); + var comm; + if (dotls == 1) { + comm = CreateWsmanComm(dev.nodeid, 16993, user, pass, 1, null, parent.mpsserver); // Perform TLS + comm.xtlsFingerprint = 0; // Perform no certificate checking + } else { + comm = CreateWsmanComm(dev.nodeid, 16992, user, pass, 0, null, parent.mpsserver); // No TLS + } + var wsstack = WsmanStackCreateService(comm); + dev.amtstack = AmtStackCreateService(wsstack); + dev.amtstack.dev = dev; + obj.activeLocalConnections[dev.host] = dev; + dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], attemptLocalConnectResponse); + dev.conntype = 2; // CIRA + + return; // If CIRA is connected, don't try any other methods. + } + + // Handle the case where the Intel AMT local scanner found the device (conn & 4) if (((dev.conn & 4) != 0) && (typeof dev.host == 'string')) { // Since we don't allow two or more connections to the same host, check if a pending connection is active. if (obj.activeLocalConnections[dev.host] != null) { @@ -218,12 +258,15 @@ module.exports.CreateAmtManager = function(parent) { dev.amtstack = AmtStackCreateService(wsstack); dev.amtstack.dev = dev; obj.activeLocalConnections[dev.host] = dev; - dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], attemptLocalConectResponse); + dev.amtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], attemptLocalConnectResponse); + dev.conntype = 1; // LOCAL } } } - function attemptLocalConectResponse(stack, name, responses, status) { + function attemptLocalConnectResponse(stack, name, responses, status) { + console.log('attemptLocalConnectResponse', status); + // Release active connection to this host. delete obj.activeLocalConnections[stack.wsman.comm.host]; @@ -255,8 +298,8 @@ module.exports.CreateAmtManager = function(parent) { fetchPowerState(dev); } else { // We got a bad response - if ((dev.tlsfail !== true) && (status == 408)) { - // TLS error, try again without TLS + if ((dev.conntype == 1) && (dev.tlsfail !== true) && (status == 408)) { + // TLS error on a local connection, try again without TLS dev.tlsfail = true; attemptInitialContact(dev.nodeid, dev); return; } else if (status == 401) { // Authentication error, see if we can use alternative credentials diff --git a/apfserver.js b/apfserver.js index f25268ab..26f26253 100644 --- a/apfserver.js +++ b/apfserver.js @@ -641,13 +641,14 @@ module.exports.CreateApfServer = function (parent, db, args) { } } - obj.SetupCiraChannelToHost = function (host, targetport) { - var apfconn = obj.apfConnections[host]; + // Setup a new channel to a nodeid + obj.SetupChannelToNode = function (nodeid, targetport) { + var apfconn = obj.apfConnections[nodeid]; if (apfconn == null) return null; - return obj.SetupCiraChannel(apfconn, targetport); + return obj.SetupChannel(apfconn, targetport); } - obj.SetupCiraChannel = function (socket, targetport) { + obj.SetupChannel = function (socket, targetport) { var sourceport = (socket.tag.nextsourceport++ % 30000) + 1024; var cirachannel = { targetport: targetport, channelid: socket.tag.nextchannelid++, socket: socket, state: 1, sendcredits: 0, amtpendingcredits: 0, amtCiraWindow: 0, ciraWindow: 32768 }; SendChannelOpen(socket, false, cirachannel.channelid, cirachannel.ciraWindow, socket.tag.host, targetport, "1.2.3.4", sourceport); diff --git a/mpsserver.js b/mpsserver.js index 3b81cbf5..58add1e9 100644 --- a/mpsserver.js +++ b/mpsserver.js @@ -142,6 +142,16 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) { var socketErrorCount = 0; var maxDomainDevicesReached = 0; + // Delay setting the connectivity state by 300ms to allow time for CIRA port mappings to be established + // Report power state as "present" (7) until Intel AMT manager starts polling for power state. + function delayedSetConnectivityState(meshid, nodeid, connectTime) { + var f = function setConnFunc() { if (obj.ciraConnections[setConnFunc.nodeid] != null) { obj.parent.SetConnectivityState(setConnFunc.meshid, setConnFunc.nodeid, setConnFunc.connectTime, 2, 7); } } + f.nodeid = nodeid; + f.meshid = meshid; + f.connectTime = connectTime; + setTimeout(f, 300); + } + // Return statistics about this MPS server obj.getStats = function () { return { @@ -324,7 +334,8 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) { // Add the connection to the MPS connection list obj.ciraConnections[socket.tag.nodeid] = socket; - 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. + //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. + delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime); } }); return; @@ -354,7 +365,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) { // Add the connection to the MPS connection list obj.ciraConnections[socket.tag.nodeid] = socket; - 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. + delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime); }); } else { // This node connected without certificate authentication, use password auth @@ -372,7 +383,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) { } }); - // Process one AFP command + // Process one APF command function ProcessCommand(socket) { var cmd = socket.tag.accumulator.charCodeAt(0); var len = socket.tag.accumulator.length; @@ -462,7 +473,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) { // Add the connection to the MPS connection list obj.ciraConnections[socket.tag.nodeid] = socket; - 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. + delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime); SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection } }); @@ -486,7 +497,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) { // Add the connection to the MPS connection list obj.ciraConnections[socket.tag.nodeid] = socket; - 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. + delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime); SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection }); } else if (mesh.mtype == 2) { // If this is a agent mesh, search the mesh for this device UUID @@ -525,7 +536,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) { // Add the connection to the MPS connection list obj.ciraConnections[socket.tag.nodeid] = socket; - 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. + delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime); SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection }); } else { // Unknown mesh type @@ -866,13 +877,15 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) { } } - obj.SetupCiraChannelToHost = function (host, targetport) { - var ciraconn = obj.ciraConnections[host]; + // Setup a new channel to a nodeid + obj.SetupChannelToNode = function (nodeid, targetport) { + var ciraconn = obj.ciraConnections[nodeid]; if (ciraconn == null) return null; - return obj.SetupCiraChannel(ciraconn, targetport); + return obj.SetupChannel(ciraconn, targetport); } - obj.SetupCiraChannel = function (socket, targetport) { + // Setup a new channel + obj.SetupChannel = function (socket, targetport) { var sourceport = (socket.tag.nextsourceport++ % 30000) + 1024; var cirachannel = { targetport: targetport, channelid: socket.tag.nextchannelid++, socket: socket, state: 1, sendcredits: 0, amtpendingcredits: 0, amtCiraWindow: 0, ciraWindow: 32768 }; SendChannelOpen(socket, false, cirachannel.channelid, cirachannel.ciraWindow, socket.tag.host, targetport, "1.2.3.4", sourceport); diff --git a/webserver.js b/webserver.js index 7ce13db3..747805fd 100644 --- a/webserver.js +++ b/webserver.js @@ -3390,7 +3390,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { if ((port == 16993) || (port == 16995)) { // Perform TLS - ( TODO: THIS IS BROKEN on Intel AMT v7 but works on v10, Not sure why. Well, could be broken TLS 1.0 in firmware ) var ser = new SerialTunnel(); - var chnl = parent.mpsserver.SetupCiraChannel(ciraconn, port); + var chnl = parent.mpsserver.SetupChannel(ciraconn, port); // Let's chain up the TLSSocket <-> SerialTunnel <-> CIRA APF (chnl) // Anything that needs to be forwarded by SerialTunnel will be encapsulated by chnl write @@ -3436,7 +3436,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { ws.forwardclient.xtls = 1; } else { // Without TLS - ws.forwardclient = parent.mpsserver.SetupCiraChannel(ciraconn, port); + ws.forwardclient = parent.mpsserver.SetupChannel(ciraconn, port); ws.forwardclient.xtls = 0; ws._socket.resume(); }