amtscanner.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. /**
  2. * @description MeshCentral Intel(R) AMT Local Scanner
  3. * @author Ylian Saint-Hilaire & Joko Sastriawan
  4. * @copyright Intel Corporation 2018-2022
  5. * @license Apache-2.0
  6. * @version v0.0.1
  7. */
  8. /*jslint node: true */
  9. /*jshint node: true */
  10. /*jshint strict:false */
  11. /*jshint -W097 */
  12. /*jshint esversion: 6 */
  13. "use strict";
  14. // Construct a Intel AMT Scanner object
  15. module.exports.CreateAmtScanner = function (parent) {
  16. var obj = {};
  17. obj.active = false;
  18. obj.parent = parent;
  19. obj.net = require('net');
  20. obj.tls = require('tls');
  21. obj.dns = require('dns');
  22. obj.dgram = require('dgram');
  23. obj.common = require('./common.js');
  24. obj.servers = {};
  25. obj.rserver = {};
  26. obj.rpacket = null;
  27. obj.tagToId = {}; // Tag --> { lastpong: time, id: NodeId }
  28. obj.scanTable = {}; // NodeId --> ScanInfo : { lastping: time, lastpong: time, nodeinfo:{node} }
  29. obj.scanTableTags = {}; // Tag --> ScanInfo
  30. obj.pendingSends = []; // We was to stagger the sends using a 10ms timer
  31. obj.pendingSendTimer = null;
  32. obj.mainTimer = null;
  33. obj.nextTag = 0;
  34. const PeriodicScanTime = 30000; // Interval between scan sweeps
  35. const PeriodicScanTimeout = 65000; // After this time, timeout the device.
  36. const constants = (require('crypto').constants ? require('crypto').constants : require('constants')); // require('constants') is deprecated in Node 11.10, use require('crypto').constants instead.
  37. // Build a RMCP packet with a given tag field
  38. obj.buildRmcpPing = function (tag) {
  39. var packet = Buffer.from(obj.common.hex2rstr('06000006000011BE80000000'), 'ascii');
  40. packet[9] = tag;
  41. return packet;
  42. };
  43. // Start scanning for local network Intel AMT computers
  44. obj.start = function () {
  45. obj.active = true;
  46. obj.performScan();
  47. obj.mainTimer = setInterval(obj.performScan, PeriodicScanTime);
  48. return obj;
  49. };
  50. // Stop scanning for local network Intel AMT computers
  51. obj.stop = function () {
  52. obj.active = false;
  53. for (var i in obj.servers) { obj.servers[i].close(); } // Stop all servers
  54. obj.servers = {};
  55. if (obj.mainTimer != null) { clearInterval(obj.mainTimer); obj.mainTimer = null; }
  56. };
  57. // Scan for Intel AMT computers using network multicast
  58. obj.performRangeScan = function (userid, rangestr) {
  59. if (obj.rpacket == null) { obj.rpacket = obj.buildRmcpPing(0); }
  60. var range = obj.parseIpv4Range(rangestr);
  61. //console.log(obj.IPv4NumToStr(range.min), obj.IPv4NumToStr(range.max));
  62. if (range == null || (range.min > range.max)) return false;
  63. var rangeinfo = { id: userid, range: rangestr, min: range.min, max: range.max, results: {} };
  64. obj.rserver[userid] = rangeinfo;
  65. rangeinfo.server = obj.dgram.createSocket("udp4");
  66. rangeinfo.server.bind(0);
  67. rangeinfo.server.on('error', (err) => { console.log(err); });
  68. rangeinfo.server.on('message', function (data, rinfo) { obj.parseRmcpPacket(data, rinfo, 0, obj.reportMachineState, rangeinfo); });
  69. rangeinfo.server.on('listening', function() { for (var i = rangeinfo.min; i <= rangeinfo.max; i++) { rangeinfo.server.send(obj.rpacket, 623, obj.IPv4NumToStr(i)); } });
  70. rangeinfo.timer = setTimeout(function () { // ************************* USE OF OUTER VARS!!!!!!!!!!!!!!!
  71. obj.parent.DispatchEvent(['*', userid], obj, { action: 'scanamtdevice', range: rangeinfo.range, results: rangeinfo.results, nolog: 1 });
  72. rangeinfo.server.close();
  73. delete rangeinfo.server;
  74. }, 3000);
  75. return true;
  76. };
  77. // Parse range, used to parse "ip", "ip/mask" or "ip-ip" notation.
  78. // Return the start and end value of the scan
  79. obj.parseIpv4Range = function (range) {
  80. if (range == undefined || range == null) return null;
  81. var x = range.split('-');
  82. if (x.length == 2) { return { min: obj.parseIpv4Addr(x[0]), max: obj.parseIpv4Addr(x[1]) }; }
  83. x = range.split('/');
  84. if (x.length == 2) {
  85. var ip = obj.parseIpv4Addr(x[0]), masknum = parseInt(x[1]), mask = 0;
  86. if (masknum <= 16 || masknum > 32) return null;
  87. masknum = 32 - masknum;
  88. for (var i = 0; i < masknum; i++) { mask = (mask << 1); mask++; }
  89. return { min: ip & (0xFFFFFFFF - mask), max: (ip & (0xFFFFFFFF - mask)) + mask };
  90. }
  91. x = obj.parseIpv4Addr(range);
  92. if (x == null) return null;
  93. return { min: x, max: x };
  94. };
  95. // Parse IP address. Takes a
  96. obj.parseIpv4Addr = function (addr) {
  97. var x = addr.split('.');
  98. if (x.length == 4) { return (parseInt(x[0]) << 24) + (parseInt(x[1]) << 16) + (parseInt(x[2]) << 8) + (parseInt(x[3]) << 0); }
  99. return null;
  100. };
  101. // IP address number to string
  102. obj.IPv4NumToStr = function (num) {
  103. return ((num >> 24) & 0xFF) + '.' + ((num >> 16) & 0xFF) + '.' + ((num >> 8) & 0xFF) + '.' + (num & 0xFF);
  104. };
  105. /*
  106. // Sample we could use to optimize DNS resolving, may not be needed at all.
  107. obj.BatchResolvePendingMax = 1;
  108. obj.BatchResolvePendingCount = 0;
  109. obj.BatchResolveResults = {};
  110. obj.BatchResolve = function (hostname) {
  111. var r = null;
  112. hostname = hostname.toLowerCase();
  113. if ((hostname == '127.0.0.1') || (hostname == '::1') || (hostname == 'localhost')) return null; // Don't scan localhost
  114. if (obj.net.isIP(hostname) > 0) return hostname; // This is an IP address, already resolved.
  115. if (obj.BatchResolveResults[hostname]) {
  116. if ((obj.BatchResolveResults[hostname].f == 0) || (obj.BatchResolveResults[hostname].f == -1)) {
  117. // Already resolving this one or an error occured during resolve, re-check every 30 minutes.
  118. if (((Date.now() - obj.BatchResolveResults[hostname].t) < 1800000) || (obj.BatchResolvePendingCount >= obj.BatchResolvePendingMax)) { return null; }
  119. } else {
  120. // We are to try to re-resolve every 30 minutes
  121. if (((Date.now() - obj.BatchResolveResults[hostname].t) < 1800000) || (obj.BatchResolvePendingCount >= obj.BatchResolvePendingMax)) { return obj.BatchResolveResults[hostname].a; }
  122. r = obj.BatchResolveResults[hostname].a;
  123. }
  124. }
  125. if (obj.BatchResolvePendingCount >= obj.BatchResolvePendingMax) return null; // Don't resolve more than 10 names at any given time.
  126. console.log('Resolve: ' + hostname);
  127. obj.BatchResolvePendingCount++;
  128. obj.BatchResolveResults[hostname] = { f: 0, t: Date.now() }; // Mark are resolving
  129. obj.dns.lookup(hostname, (err, address, family) => {
  130. obj.BatchResolvePendingCount--;
  131. if (err != null) {
  132. console.log('Resolve error: ' + hostname);
  133. obj.BatchResolveResults[hostname] = { f: -1 }; // Mark this as a resolve error
  134. } else {
  135. console.log('Resolved: %s = %j, family: IPv%s', hostname, address, family);
  136. obj.BatchResolveResults[hostname] = { a: address, f: family, t: Date.now() };
  137. }
  138. });
  139. return r;
  140. };
  141. */
  142. obj.ResolveName = function (hostname, func) {
  143. if ((hostname == '127.0.0.1') || (hostname == '::1') || (hostname == 'localhost')) { func(hostname, null); } // Don't scan localhost
  144. if (obj.net.isIP(hostname) > 0) { func(hostname, hostname); return; } // This is an IP address, already resolved.
  145. obj.dns.lookup(hostname, function (err, address, family) { if (err == null) { func(hostname, address); } else { func(hostname, null); } });
  146. };
  147. // Look for all Intel AMT computers that may be locally reachable and poll their presence
  148. obj.performScan = function () {
  149. if (obj.active == false) { return false; }
  150. obj.parent.db.getLocalAmtNodes(function (err, docs) { // TODO: handler more than 10 computer scan at the same time. DNS resolved may need to be a seperate module.
  151. for (var i in obj.scanTable) { obj.scanTable[i].present = false; }
  152. if (err == null && docs.length > 0) {
  153. for (var i in docs) {
  154. var doc = docs[i], host = doc.host.toLowerCase();
  155. const ciraConnections = obj.parent.mpsserver ? obj.parent.mpsserver.GetConnectionToNode(doc._id, null, true) : null; // See if any OOB connections are present
  156. if ((host != '127.0.0.1') && (host != '::1') && (host.toLowerCase() != 'localhost') && (ciraConnections == null)) {
  157. var scaninfo = obj.scanTable[doc._id];
  158. if (scaninfo == null) {
  159. var tag = obj.nextTag++;
  160. obj.scanTableTags[tag] = obj.scanTable[doc._id] = scaninfo = { nodeinfo: doc, present: true, tag: tag, state: 0 };
  161. //console.log('Scan ' + host + ', state=' + scaninfo.state + ', delta=' + delta);
  162. } else {
  163. scaninfo.present = true;
  164. var delta = Date.now() - scaninfo.lastpong;
  165. //console.log('Rescan ' + host + ', state=' + scaninfo.state + ', delta=' + delta);
  166. if ((scaninfo.state == 1) && (delta >= PeriodicScanTimeout)) {
  167. // More than 2 minutes without a response, mark the node as unknown state
  168. scaninfo.state = 0;
  169. obj.parent.ClearConnectivityState(scaninfo.nodeinfo.meshid, scaninfo.nodeinfo._id, 4, null, { name: doc.name }); // Clear connectivity state
  170. if (obj.parent.amtManager != null) { obj.parent.amtManager.stopAmtManagement(scaninfo.nodeinfo._id, 3, scaninfo.nodeinfo.host); }
  171. } else if ((scaninfo.tcp == null) && ((scaninfo.state == 0) || isNaN(delta) || (delta > PeriodicScanTime))) {
  172. // More than 30 seconds without a response, try TCP detection
  173. obj.checkTcpPresence(host, (doc.intelamt.tls == 1) ? 16993 : 16992, scaninfo, function (tag, result, version) {
  174. // TODO: It is bad that "obj" is being accessed within this function.
  175. if (result == false) return;
  176. tag.lastpong = Date.now();
  177. if (tag.state == 0) {
  178. tag.state = 1;
  179. obj.parent.SetConnectivityState(tag.nodeinfo.meshid, tag.nodeinfo._id, tag.lastpong, 4, 7, null, { name: doc.name }); // Report power state as "present" (7).
  180. if (version != null) { obj.changeAmtState(tag.nodeinfo._id, version, 2, tag.nodeinfo.intelamt.tls); }
  181. if (obj.parent.amtManager != null) { obj.parent.amtManager.startAmtManagement(tag.nodeinfo._id, 3, tag.nodeinfo.host); }
  182. }
  183. });
  184. }
  185. }
  186. // Start scanning this node
  187. scaninfo.lastping = Date.now();
  188. obj.checkAmtPresence(host, scaninfo.tag);
  189. }
  190. }
  191. }
  192. for (var i in obj.scanTable) {
  193. if (obj.scanTable[i].present == false) {
  194. // Stop scanning this node
  195. delete obj.scanTableTags[obj.scanTable[i].tag];
  196. delete obj.scanTable[i];
  197. }
  198. }
  199. });
  200. return true;
  201. };
  202. // Look for all Intel AMT computers that may be locally reachable and poll their presence
  203. obj.performSpecificScan = function (node) {
  204. if ((node == null) || (node.host == null)) return;
  205. var host = node.host.toLowerCase();
  206. const ciraConnections = obj.parent.mpsserver ? obj.parent.mpsserver.GetConnectionToNode(node._id, null, true) : null; // See if any OOB connections are present
  207. if ((host != '127.0.0.1') && (host != '::1') && (host.toLowerCase() != 'localhost') && (ciraConnections == null)) {
  208. obj.checkTcpPresence(host, (node.intelamt.tls == 1) ? 16993 : 16992, { nodeinfo: node }, function (tag, result, version) {
  209. if ((result == true) && (obj.parent.amtManager != null)) { obj.parent.amtManager.startAmtManagement(tag.nodeinfo._id, 3, tag.nodeinfo.host); }
  210. });
  211. }
  212. };
  213. // Check the presense of a specific Intel AMT computer using RMCP
  214. obj.checkAmtPresence = function (host, tag) { obj.ResolveName(host, function (hostname, ip) { obj.checkAmtPresenceEx(ip, tag); }); };
  215. // Check the presense of a specific Intel AMT computer using RMCP
  216. obj.checkAmtPresenceEx = function (host, tag) {
  217. if (host == null) return;
  218. var serverid = Math.floor(tag / 255);
  219. var servertag = (tag % 255);
  220. var packet = obj.buildRmcpPing(servertag);
  221. var server = obj.servers[serverid];
  222. if (server == undefined) {
  223. // Start new server
  224. server = obj.dgram.createSocket('udp4');
  225. server.on('error', (err) => { });
  226. server.on('message', (data, rinfo) => { obj.parseRmcpPacket(data, rinfo, serverid, obj.changeConnectState, null); });
  227. server.on('listening', () => {
  228. obj.pendingSends.push([server, packet, host]);
  229. if (obj.pendingSendTimer == null) { obj.pendingSendTimer = setInterval(obj.sendPendingPacket, 10); }
  230. });
  231. server.bind(0);
  232. obj.servers[serverid] = server;
  233. } else {
  234. // Use existing server
  235. obj.pendingSends.push([server, packet, host]);
  236. if (obj.pendingSendTimer == null) { obj.pendingSendTimer = setInterval(obj.sendPendingPacket, 10); }
  237. }
  238. };
  239. // Send a pending RMCP packet
  240. obj.sendPendingPacket = function () {
  241. try {
  242. var p = obj.pendingSends.shift();
  243. if (p != undefined) {
  244. p[0].send(p[1], 623, p[2]);
  245. p[0].send(p[1], 623, p[2]);
  246. } else {
  247. clearInterval(obj.pendingSendTimer);
  248. obj.pendingSendTimer = null;
  249. }
  250. } catch (e) { }
  251. };
  252. // Parse RMCP packet
  253. obj.parseRmcpPacket = function (data, rinfo, serverid, func, user) {
  254. if (data == null || data.length < 20) return;
  255. if (((data[12] == 0) || (data[13] != 0) || (data[14] != 1) || (data[15] != 0x57)) && (data[21] & 32)) {
  256. var servertag = data[9];
  257. var tag = (serverid * 255) + servertag;
  258. var minorVersion = data[18] & 0x0F;
  259. var majorVersion = (data[18] >> 4) & 0x0F;
  260. var provisioningState = data[19] & 0x03; // Pre = 0, In = 1, Post = 2
  261. var openPort = (data[16] * 256) + data[17];
  262. var dualPorts = ((data[19] & 0x04) != 0) ? true : false;
  263. var openPorts = [openPort];
  264. if (dualPorts == true) { openPorts = [16992, 16993]; }
  265. if (provisioningState <= 2) { func(tag, minorVersion, majorVersion, provisioningState, openPort, dualPorts, rinfo, user); }
  266. }
  267. };
  268. // Use the RMCP packet to change the computer state
  269. obj.changeConnectState = function (tag, minorVersion, majorVersion, provisioningState, openPort, dualPorts, rinfo, user) {
  270. //var provisioningStates = { 0: 'Pre', 1: 'in', 2: 'Post' };
  271. //var provisioningStateStr = provisioningStates[provisioningState];
  272. //console.log('Intel AMT ' + majorVersion + '.' + minorVersion + ', ' + provisioningStateStr + '-Provisioning at ' + rinfo.address + ', Open Ports: [' + openPort + '], tag: ' + tag + ', dualPorts: ' + dualPorts);
  273. var scaninfo = obj.scanTableTags[tag];
  274. if (scaninfo != undefined) {
  275. scaninfo.lastpong = Date.now();
  276. if (scaninfo.state == 0) {
  277. scaninfo.state = 1;
  278. if ((openPort == 16993) || (dualPorts == true)) { scaninfo.nodeinfo.intelamt.tls = 1; }
  279. else if (openPort == 16992) { scaninfo.nodeinfo.intelamt.tls = 0; }
  280. if (majorVersion > 0) { // Older versions of Intel AMT report the AMT version.
  281. scaninfo.nodeinfo.intelamt.ver = majorVersion + '.' + minorVersion;
  282. scaninfo.nodeinfo.intelamt.state = provisioningState;
  283. }
  284. obj.parent.SetConnectivityState(scaninfo.nodeinfo.meshid, scaninfo.nodeinfo._id, scaninfo.lastpong, 4, 7, null, { name: scaninfo.nodeinfo.name }); // Report power state as "present" (7).
  285. obj.changeAmtState(scaninfo.nodeinfo._id, scaninfo.nodeinfo.intelamt.ver, provisioningState, scaninfo.nodeinfo.intelamt.tls);
  286. if (obj.parent.amtManager != null) { obj.parent.amtManager.startAmtManagement(scaninfo.nodeinfo._id, 3, scaninfo.nodeinfo.host); }
  287. }
  288. }
  289. };
  290. // Use the RMCP packet to change the computer state
  291. obj.reportMachineState = function (tag, minorVersion, majorVersion, provisioningState, openPort, dualPorts, rinfo, user) {
  292. //var provisioningStates = { 0: 'Pre', 1: 'in', 2: 'Post' };
  293. //var provisioningStateStr = provisioningStates[provisioningState];
  294. //console.log(rinfo.address + ': Intel AMT ' + majorVersion + '.' + minorVersion + ', ' + provisioningStateStr + '-Provisioning, Open Ports: [' + openPorts.join(', ') + ']');
  295. obj.dns.reverse(rinfo.address, function (err, hostnames) {
  296. if ((err == null) && (hostnames != null) && (hostnames.length > 0)) {
  297. user.results[rinfo.address] = { ver: majorVersion + '.' + minorVersion, tls: (((openPort == 16993) || (dualPorts == true)) ? 1 : 0), state: provisioningState, hostname: hostnames[0], hosttype: 'host' };
  298. } else {
  299. user.results[rinfo.address] = { ver: majorVersion + '.' + minorVersion, tls: (((openPort == 16993) || (dualPorts == true)) ? 1 : 0), state: provisioningState, hostname: rinfo.address, hosttype: 'addr' };
  300. }
  301. });
  302. };
  303. // Change Intel AMT information in the database and event the changes
  304. obj.changeAmtState = function (nodeid, version, provisioningState, tls) {
  305. //console.log('changeAmtState', nodeid, version, provisioningState, tls);
  306. obj.parent.db.Get(nodeid, function (err, nodes) {
  307. if (nodes.length != 1) return;
  308. var node = nodes[0];
  309. // Get the mesh for this device
  310. obj.parent.db.Get(node.meshid, function (err, meshes) {
  311. if (meshes.length != 1) return;
  312. var mesh = meshes[0];
  313. // Ready the node change event
  314. var changes = [], event = { etype: 'node', action: 'changenode', nodeid: node._id };
  315. event.msg = +": ";
  316. // Make the change & save
  317. var change = false;
  318. if (node.intelamt == undefined) { node.intelamt = {}; }
  319. if (node.intelamt.tls != tls) { node.intelamt.tls = tls; change = true; changes.push(tls == 1 ? 'TLS' : 'NoTLS'); }
  320. if (obj.compareAmtVersionStr(node.intelamt.ver, version)) { node.intelamt.ver = version; change = true; changes.push('AMT Version ' + version); }
  321. if (node.intelamt.state != provisioningState) { node.intelamt.state = provisioningState; change = true; changes.push('AMT State'); }
  322. if (change == true) {
  323. // Make the change in the database
  324. obj.parent.db.Set(node);
  325. // Event the node change
  326. event.msg = 'Intel&reg; AMT changed device ' + node.name + ' from mesh ' + mesh.name + ': ' + changes.join(', ');
  327. event.node = obj.parent.webserver.CloneSafeNode(node);
  328. if (obj.parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
  329. obj.parent.DispatchEvent(['*', node.meshid], obj, event);
  330. }
  331. });
  332. });
  333. };
  334. // Return true if we should change the Intel AMT version number
  335. obj.compareAmtVersionStr = function (oldVer, newVer) {
  336. if (oldVer == newVer) return false; // Versions are same already, don't update.
  337. if (newVer == undefined || newVer == null) return false; // New version is bad, don't update it.
  338. if (oldVer == undefined || oldVer == null) return true; // Old version is no good anyway, update it.
  339. var oldVerArr = oldVer.toString().split('.');
  340. var newVerArr = newVer.toString().split('.');
  341. if ((oldVerArr.length < 2) || (newVerArr.length < 2)) return false;
  342. if ((oldVerArr[0] != newVerArr[0]) || (oldVerArr[1] != newVerArr[1])) return true;
  343. if (newVerArr.length > oldVerArr.length) return true;
  344. if ((newVerArr.length == 3) && (oldVerArr.length == 3) && (oldVerArr[2] != newVerArr[2])) return true;
  345. return false;
  346. };
  347. // Check the presense of a specific Intel AMT computer using RMCP
  348. obj.checkTcpPresence = function (host, port, scaninfo, func) { obj.ResolveName(host, function (hostname, ip) { obj.checkTcpPresenceEx(ip, port, scaninfo, func); }); };
  349. // Check that we can connect TCP to a given port
  350. obj.checkTcpPresenceEx = function (host, port, scaninfo, func) {
  351. if (host == null) return;
  352. //console.log('checkTcpPresence(' + host + ':' + port + ')');
  353. try {
  354. var client;
  355. if (port == 16992) {
  356. // Connect using TCP
  357. client = new obj.net.Socket();
  358. client.connect(port, host, function () { this.write('GET / HTTP/1.1\r\nhost: ' + host + '\r\n\r\n'); });
  359. } else {
  360. // Connect using TLS, we will switch from default TLS to TLS1-only and back if we get a connection error to support older Intel AMT.
  361. if (scaninfo.tlsoption == null) { scaninfo.tlsoption = 0; }
  362. const tlsOptions = { rejectUnauthorized: false, ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE };
  363. if (scaninfo.tlsoption == 1) { tlsOptions.secureProtocol = 'TLSv1_method'; }
  364. client = obj.tls.connect(port, host, tlsOptions, function () { this.write('GET / HTTP/1.1\r\nhost: ' + host + '\r\n\r\n'); });
  365. }
  366. client.scaninfo = scaninfo;
  367. client.func = func;
  368. client.port = port;
  369. client.setTimeout(10000);
  370. client.on('data', function (data) { var version = obj.getIntelAmtVersionFromHeaders(data.toString()); if (this.scaninfo.tcp != null) { delete this.scaninfo.tcp; try { this.destroy(); } catch (ex) { } this.func(this.scaninfo, version != null, version); } });
  371. client.on('error', function () { if (this.scaninfo.tlsoption == 0) { this.scaninfo.tlsoption = 1; } else if (this.scaninfo.tlsoption == 1) { this.scaninfo.tlsoption = 0; } if (this.scaninfo.tcp != null) { delete this.scaninfo.tcp; try { this.destroy(); } catch (ex) { } this.func(this.scaninfo, false); } });
  372. client.on('timeout', function () { if (this.scaninfo.tcp != null) { delete this.scaninfo.tcp; try { this.destroy(); } catch (ex) { } this.func(this.scaninfo, false); } });
  373. client.on('close', function () { if (this.scaninfo.tcp != null) { delete this.scaninfo.tcp; try { this.destroy(); } catch (ex) { } this.func(this.scaninfo, false); } });
  374. client.on('end', function () { if (this.scaninfo.tcp != null) { delete this.scaninfo.tcp; try { this.destroy(); } catch (ex) { } this.func(this.scaninfo, false); } });
  375. scaninfo.tcp = client;
  376. } catch (ex) { console.log(ex); }
  377. };
  378. // Return the Intel AMT version from the HTTP headers. Return null if nothing is found.
  379. obj.getIntelAmtVersionFromHeaders = function (headers) {
  380. if (headers == null || headers.length == 0) return null;
  381. var lines = headers.split('\r\n');
  382. for (var i in lines) {
  383. // Look for the Intel AMT version
  384. if (lines[i].substring(0, 46) == 'Server: Intel(R) Active Management Technology ') {
  385. // We need to check that the Intel AMT version is correct, in the "a.b.c" format
  386. var ver = lines[i].substring(46), splitver = ver.split('.');
  387. if ((splitver.length == 3 || splitver.length == 4) && ('' + parseInt(splitver[0]) === splitver[0]) && ('' + parseInt(splitver[1]) === splitver[1]) && ('' + parseInt(splitver[2]) === splitver[2])) { return (splitver[0] + '.' + splitver[1] + '.' + splitver[2]); }
  388. }
  389. }
  390. return null;
  391. };
  392. //console.log(obj.getIntelAmtVersionFromHeaders("HTTP/1.1 303 See Other\r\nLocation: /logon.htm\r\nContent-Length: 0\r\nServer: Intel(R) Active Management Technology 7.1.91\r\n\r\n"));
  393. return obj;
  394. };