2017-08-28 19:27:45 +03:00
/ * *
2018-01-04 23:15:21 +03:00
* @ description MeshCentral Intel ( R ) AMT Local Scanner
2017-08-28 19:27:45 +03:00
* @ author Ylian Saint - Hilaire & Joko Sastriawan
2022-01-24 10:21:24 +03:00
* @ copyright Intel Corporation 2018 - 2022
2018-01-04 23:15:21 +03:00
* @ license Apache - 2.0
2017-08-28 19:27:45 +03:00
* @ version v0 . 0.1
* /
2018-08-30 03:40:30 +03:00
/*jslint node: true */
/*jshint node: true */
/*jshint strict:false */
/*jshint -W097 */
/*jshint esversion: 6 */
"use strict" ;
2018-08-27 22:24:15 +03:00
2017-08-28 19:27:45 +03:00
// Construct a Intel AMT Scanner object
module . exports . CreateAmtScanner = function ( parent ) {
var obj = { } ;
obj . active = false ;
obj . parent = parent ;
2018-05-18 02:30:04 +03:00
obj . net = require ( 'net' ) ;
2018-05-19 03:29:25 +03:00
obj . tls = require ( 'tls' ) ;
2017-08-28 19:27:45 +03:00
obj . dns = require ( 'dns' ) ;
obj . dgram = require ( 'dgram' ) ;
obj . common = require ( './common.js' ) ;
obj . servers = { } ;
obj . rserver = { } ;
obj . rpacket = null ;
obj . tagToId = { } ; // Tag --> { lastpong: time, id: NodeId }
obj . scanTable = { } ; // NodeId --> ScanInfo : { lastping: time, lastpong: time, nodeinfo:{node} }
obj . scanTableTags = { } ; // Tag --> ScanInfo
obj . pendingSends = [ ] ; // We was to stagger the sends using a 10ms timer
obj . pendingSendTimer = null ;
obj . mainTimer = null ;
obj . nextTag = 0 ;
2018-05-03 21:09:29 +03:00
const PeriodicScanTime = 30000 ; // Interval between scan sweeps
const PeriodicScanTimeout = 65000 ; // After this time, timeout the device.
2019-02-27 02:49:44 +03:00
const constants = ( require ( 'crypto' ) . constants ? require ( 'crypto' ) . constants : require ( 'constants' ) ) ; // require('constants') is deprecated in Node 11.10, use require('crypto').constants instead.
2017-08-28 19:27:45 +03:00
// Build a RMCP packet with a given tag field
obj . buildRmcpPing = function ( tag ) {
2019-01-03 05:03:34 +03:00
var packet = Buffer . from ( obj . common . hex2rstr ( '06000006000011BE80000000' ) , 'ascii' ) ;
2017-08-28 19:27:45 +03:00
packet [ 9 ] = tag ;
return packet ;
2018-08-30 03:40:30 +03:00
} ;
2017-08-28 19:27:45 +03:00
// Start scanning for local network Intel AMT computers
obj . start = function ( ) {
obj . active = true ;
obj . performScan ( ) ;
obj . mainTimer = setInterval ( obj . performScan , PeriodicScanTime ) ;
return obj ;
2018-08-30 03:40:30 +03:00
} ;
2017-08-28 19:27:45 +03:00
// Stop scanning for local network Intel AMT computers
obj . stop = function ( ) {
obj . active = false ;
for ( var i in obj . servers ) { obj . servers [ i ] . close ( ) ; } // Stop all servers
obj . servers = { } ;
if ( obj . mainTimer != null ) { clearInterval ( obj . mainTimer ) ; obj . mainTimer = null ; }
2018-08-30 03:40:30 +03:00
} ;
2017-08-28 19:27:45 +03:00
// Scan for Intel AMT computers using network multicast
obj . performRangeScan = function ( userid , rangestr ) {
if ( obj . rpacket == null ) { obj . rpacket = obj . buildRmcpPing ( 0 ) ; }
var range = obj . parseIpv4Range ( rangestr ) ;
//console.log(obj.IPv4NumToStr(range.min), obj.IPv4NumToStr(range.max));
if ( range == null || ( range . min > range . max ) ) return false ;
var rangeinfo = { id : userid , range : rangestr , min : range . min , max : range . max , results : { } } ;
obj . rserver [ userid ] = rangeinfo ;
rangeinfo . server = obj . dgram . createSocket ( "udp4" ) ;
rangeinfo . server . bind ( 0 ) ;
rangeinfo . server . on ( 'error' , ( err ) => { console . log ( err ) ; } ) ;
2020-06-27 02:25:12 +03:00
rangeinfo . server . on ( 'message' , function ( data , rinfo ) { obj . parseRmcpPacket ( data , rinfo , 0 , obj . reportMachineState , rangeinfo ) ; } ) ;
rangeinfo . server . on ( 'listening' , function ( ) { for ( var i = rangeinfo . min ; i <= rangeinfo . max ; i ++ ) { rangeinfo . server . send ( obj . rpacket , 623 , obj . IPv4NumToStr ( i ) ) ; } } ) ;
rangeinfo . timer = setTimeout ( function ( ) { // ************************* USE OF OUTER VARS!!!!!!!!!!!!!!!
2017-08-28 19:27:45 +03:00
obj . parent . DispatchEvent ( [ '*' , userid ] , obj , { action : 'scanamtdevice' , range : rangeinfo . range , results : rangeinfo . results , nolog : 1 } ) ;
rangeinfo . server . close ( ) ;
delete rangeinfo . server ;
} , 3000 ) ;
return true ;
2018-08-30 03:40:30 +03:00
} ;
2017-08-28 19:27:45 +03:00
// Parse range, used to parse "ip", "ip/mask" or "ip-ip" notation.
// Return the start and end value of the scan
obj . parseIpv4Range = function ( range ) {
if ( range == undefined || range == null ) return null ;
var x = range . split ( '-' ) ;
if ( x . length == 2 ) { return { min : obj . parseIpv4Addr ( x [ 0 ] ) , max : obj . parseIpv4Addr ( x [ 1 ] ) } ; }
x = range . split ( '/' ) ;
if ( x . length == 2 ) {
var ip = obj . parseIpv4Addr ( x [ 0 ] ) , masknum = parseInt ( x [ 1 ] ) , mask = 0 ;
if ( masknum <= 16 || masknum > 32 ) return null ;
masknum = 32 - masknum ;
for ( var i = 0 ; i < masknum ; i ++ ) { mask = ( mask << 1 ) ; mask ++ ; }
return { min : ip & ( 0xFFFFFFFF - mask ) , max : ( ip & ( 0xFFFFFFFF - mask ) ) + mask } ;
}
x = obj . parseIpv4Addr ( range ) ;
if ( x == null ) return null ;
return { min : x , max : x } ;
2018-08-30 03:40:30 +03:00
} ;
2017-08-28 19:27:45 +03:00
// Parse IP address. Takes a
obj . parseIpv4Addr = function ( addr ) {
var x = addr . split ( '.' ) ;
if ( x . length == 4 ) { return ( parseInt ( x [ 0 ] ) << 24 ) + ( parseInt ( x [ 1 ] ) << 16 ) + ( parseInt ( x [ 2 ] ) << 8 ) + ( parseInt ( x [ 3 ] ) << 0 ) ; }
return null ;
2018-08-30 03:40:30 +03:00
} ;
2017-08-28 19:27:45 +03:00
// IP address number to string
obj . IPv4NumToStr = function ( num ) {
return ( ( num >> 24 ) & 0xFF ) + '.' + ( ( num >> 16 ) & 0xFF ) + '.' + ( ( num >> 8 ) & 0xFF ) + '.' + ( num & 0xFF ) ;
2018-08-30 03:40:30 +03:00
} ;
2017-08-28 19:27:45 +03:00
2018-07-31 00:21:03 +03:00
/ *
// Sample we could use to optimize DNS resolving, may not be needed at all.
obj . BatchResolvePendingMax = 1 ;
obj . BatchResolvePendingCount = 0 ;
obj . BatchResolveResults = { } ;
obj . BatchResolve = function ( hostname ) {
var r = null ;
hostname = hostname . toLowerCase ( ) ;
if ( ( hostname == '127.0.0.1' ) || ( hostname == '::1' ) || ( hostname == 'localhost' ) ) return null ; // Don't scan localhost
if ( obj . net . isIP ( hostname ) > 0 ) return hostname ; // This is an IP address, already resolved.
if ( obj . BatchResolveResults [ hostname ] ) {
if ( ( obj . BatchResolveResults [ hostname ] . f == 0 ) || ( obj . BatchResolveResults [ hostname ] . f == - 1 ) ) {
// Already resolving this one or an error occured during resolve, re-check every 30 minutes.
if ( ( ( Date . now ( ) - obj . BatchResolveResults [ hostname ] . t ) < 1800000 ) || ( obj . BatchResolvePendingCount >= obj . BatchResolvePendingMax ) ) { return null ; }
} else {
// We are to try to re-resolve every 30 minutes
if ( ( ( Date . now ( ) - obj . BatchResolveResults [ hostname ] . t ) < 1800000 ) || ( obj . BatchResolvePendingCount >= obj . BatchResolvePendingMax ) ) { return obj . BatchResolveResults [ hostname ] . a ; }
r = obj . BatchResolveResults [ hostname ] . a ;
}
}
if ( obj . BatchResolvePendingCount >= obj . BatchResolvePendingMax ) return null ; // Don't resolve more than 10 names at any given time.
console . log ( 'Resolve: ' + hostname ) ;
obj . BatchResolvePendingCount ++ ;
obj . BatchResolveResults [ hostname ] = { f : 0 , t : Date . now ( ) } ; // Mark are resolving
obj . dns . lookup ( hostname , ( err , address , family ) => {
obj . BatchResolvePendingCount -- ;
if ( err != null ) {
console . log ( 'Resolve error: ' + hostname ) ;
obj . BatchResolveResults [ hostname ] = { f : - 1 } ; // Mark this as a resolve error
} else {
console . log ( 'Resolved: %s = %j, family: IPv%s' , hostname , address , family ) ;
obj . BatchResolveResults [ hostname ] = { a : address , f : family , t : Date . now ( ) } ;
}
} ) ;
return r ;
2018-08-30 03:40:30 +03:00
} ;
2018-07-31 00:21:03 +03:00
* /
obj . ResolveName = function ( hostname , func ) {
if ( ( hostname == '127.0.0.1' ) || ( hostname == '::1' ) || ( hostname == 'localhost' ) ) { func ( hostname , null ) ; } // Don't scan localhost
if ( obj . net . isIP ( hostname ) > 0 ) { func ( hostname , hostname ) ; return ; } // This is an IP address, already resolved.
obj . dns . lookup ( hostname , function ( err , address , family ) { if ( err == null ) { func ( hostname , address ) ; } else { func ( hostname , null ) ; } } ) ;
2018-08-30 03:40:30 +03:00
} ;
2018-07-31 00:21:03 +03:00
// Look for all Intel AMT computers that may be locally reachable and poll their presence
2017-08-28 19:27:45 +03:00
obj . performScan = function ( ) {
2018-07-27 23:53:50 +03:00
if ( obj . active == false ) { return false ; }
2018-07-31 00:21:03 +03:00
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.
2017-08-28 19:27:45 +03:00
for ( var i in obj . scanTable ) { obj . scanTable [ i ] . present = false ; }
if ( err == null && docs . length > 0 ) {
for ( var i in docs ) {
2018-05-18 02:30:04 +03:00
var doc = docs [ i ] , host = doc . host . toLowerCase ( ) ;
2020-10-10 01:44:09 +03:00
const ciraConnections = obj . parent . mpsserver ? obj . parent . mpsserver . GetConnectionToNode ( doc . _id , null , true ) : null ; // See if any OOB connections are present
if ( ( host != '127.0.0.1' ) && ( host != '::1' ) && ( host . toLowerCase ( ) != 'localhost' ) && ( ciraConnections == null ) ) {
2017-08-28 19:27:45 +03:00
var scaninfo = obj . scanTable [ doc . _id ] ;
2021-02-23 01:41:54 +03:00
if ( scaninfo == null ) {
2017-08-28 19:27:45 +03:00
var tag = obj . nextTag ++ ;
obj . scanTableTags [ tag ] = obj . scanTable [ doc . _id ] = scaninfo = { nodeinfo : doc , present : true , tag : tag , state : 0 } ;
2018-05-18 02:30:04 +03:00
//console.log('Scan ' + host + ', state=' + scaninfo.state + ', delta=' + delta);
2017-08-28 19:27:45 +03:00
} else {
scaninfo . present = true ;
2018-05-18 02:30:04 +03:00
var delta = Date . now ( ) - scaninfo . lastpong ;
//console.log('Rescan ' + host + ', state=' + scaninfo.state + ', delta=' + delta);
if ( ( scaninfo . state == 1 ) && ( delta >= PeriodicScanTimeout ) ) {
// More than 2 minutes without a response, mark the node as unknown state
scaninfo . state = 0 ;
2021-10-10 22:43:20 +03:00
obj . parent . ClearConnectivityState ( scaninfo . nodeinfo . meshid , scaninfo . nodeinfo . _id , 4 , null , { name : doc . name } ) ; // Clear connectivity state
2020-10-16 02:08:36 +03:00
if ( obj . parent . amtManager != null ) { obj . parent . amtManager . stopAmtManagement ( scaninfo . nodeinfo . _id , 3 , scaninfo . nodeinfo . host ) ; }
2018-05-18 02:30:04 +03:00
} else if ( ( scaninfo . tcp == null ) && ( ( scaninfo . state == 0 ) || isNaN ( delta ) || ( delta > PeriodicScanTime ) ) ) {
// More than 30 seconds without a response, try TCP detection
2018-05-19 03:29:25 +03:00
obj . checkTcpPresence ( host , ( doc . intelamt . tls == 1 ) ? 16993 : 16992 , scaninfo , function ( tag , result , version ) {
2018-08-30 03:40:30 +03:00
// TODO: It is bad that "obj" is being accessed within this function.
2018-05-18 02:30:04 +03:00
if ( result == false ) return ;
tag . lastpong = Date . now ( ) ;
2018-05-19 03:29:25 +03:00
if ( tag . state == 0 ) {
tag . state = 1 ;
2021-10-10 22:43:20 +03:00
obj . parent . SetConnectivityState ( tag . nodeinfo . meshid , tag . nodeinfo . _id , tag . lastpong , 4 , 7 , null , { name : doc . name } ) ; // Report power state as "present" (7).
2018-05-19 03:29:25 +03:00
if ( version != null ) { obj . changeAmtState ( tag . nodeinfo . _id , version , 2 , tag . nodeinfo . intelamt . tls ) ; }
2020-10-16 02:08:36 +03:00
if ( obj . parent . amtManager != null ) { obj . parent . amtManager . startAmtManagement ( tag . nodeinfo . _id , 3 , tag . nodeinfo . host ) ; }
2018-07-31 00:21:03 +03:00
}
2018-05-18 02:30:04 +03:00
} ) ;
2017-08-28 19:27:45 +03:00
}
}
// Start scanning this node
scaninfo . lastping = Date . now ( ) ;
2018-07-31 00:21:03 +03:00
obj . checkAmtPresence ( host , scaninfo . tag ) ;
2017-08-28 19:27:45 +03:00
}
2018-08-30 03:40:30 +03:00
}
2017-08-28 19:27:45 +03:00
}
for ( var i in obj . scanTable ) {
if ( obj . scanTable [ i ] . present == false ) {
// Stop scanning this node
delete obj . scanTableTags [ obj . scanTable [ i ] . tag ] ;
delete obj . scanTable [ i ] ;
}
}
} ) ;
return true ;
2018-08-30 03:40:30 +03:00
} ;
2017-08-28 19:27:45 +03:00
2021-02-23 01:41:54 +03:00
// Look for all Intel AMT computers that may be locally reachable and poll their presence
obj . performSpecificScan = function ( node ) {
2022-01-09 22:41:58 +03:00
if ( ( node == null ) || ( node . host == null ) ) return ;
2021-02-23 01:41:54 +03:00
var host = node . host . toLowerCase ( ) ;
const ciraConnections = obj . parent . mpsserver ? obj . parent . mpsserver . GetConnectionToNode ( node . _id , null , true ) : null ; // See if any OOB connections are present
if ( ( host != '127.0.0.1' ) && ( host != '::1' ) && ( host . toLowerCase ( ) != 'localhost' ) && ( ciraConnections == null ) ) {
obj . checkTcpPresence ( host , ( node . intelamt . tls == 1 ) ? 16993 : 16992 , { nodeinfo : node } , function ( tag , result , version ) {
if ( ( result == true ) && ( obj . parent . amtManager != null ) ) { obj . parent . amtManager . startAmtManagement ( tag . nodeinfo . _id , 3 , tag . nodeinfo . host ) ; }
} ) ;
}
} ;
2018-05-18 02:30:04 +03:00
// Check the presense of a specific Intel AMT computer using RMCP
2018-08-30 03:40:30 +03:00
obj . checkAmtPresence = function ( host , tag ) { obj . ResolveName ( host , function ( hostname , ip ) { obj . checkAmtPresenceEx ( ip , tag ) ; } ) ; } ;
2018-07-31 00:21:03 +03:00
// Check the presense of a specific Intel AMT computer using RMCP
obj . checkAmtPresenceEx = function ( host , tag ) {
if ( host == null ) return ;
2017-08-28 19:27:45 +03:00
var serverid = Math . floor ( tag / 255 ) ;
var servertag = ( tag % 255 ) ;
var packet = obj . buildRmcpPing ( servertag ) ;
var server = obj . servers [ serverid ] ;
if ( server == undefined ) {
// Start new server
server = obj . dgram . createSocket ( 'udp4' ) ;
server . on ( 'error' , ( err ) => { } ) ;
server . on ( 'message' , ( data , rinfo ) => { obj . parseRmcpPacket ( data , rinfo , serverid , obj . changeConnectState , null ) ; } ) ;
server . on ( 'listening' , ( ) => {
2018-08-30 03:40:30 +03:00
obj . pendingSends . push ( [ server , packet , host ] ) ;
2017-08-28 19:27:45 +03:00
if ( obj . pendingSendTimer == null ) { obj . pendingSendTimer = setInterval ( obj . sendPendingPacket , 10 ) ; }
} ) ;
server . bind ( 0 ) ;
obj . servers [ serverid ] = server ;
} else {
// Use existing server
2018-08-30 03:40:30 +03:00
obj . pendingSends . push ( [ server , packet , host ] ) ;
2017-08-28 19:27:45 +03:00
if ( obj . pendingSendTimer == null ) { obj . pendingSendTimer = setInterval ( obj . sendPendingPacket , 10 ) ; }
}
2018-08-30 03:40:30 +03:00
} ;
2017-08-28 19:27:45 +03:00
// Send a pending RMCP packet
2018-08-30 03:40:30 +03:00
obj . sendPendingPacket = function ( ) {
2017-08-28 19:27:45 +03:00
try {
var p = obj . pendingSends . shift ( ) ;
if ( p != undefined ) {
p [ 0 ] . send ( p [ 1 ] , 623 , p [ 2 ] ) ;
p [ 0 ] . send ( p [ 1 ] , 623 , p [ 2 ] ) ;
} else {
clearInterval ( obj . pendingSendTimer ) ;
obj . pendingSendTimer = null ;
}
} catch ( e ) { }
2018-08-30 03:40:30 +03:00
} ;
2017-08-28 19:27:45 +03:00
// Parse RMCP packet
obj . parseRmcpPacket = function ( data , rinfo , serverid , func , user ) {
if ( data == null || data . length < 20 ) return ;
if ( ( ( data [ 12 ] == 0 ) || ( data [ 13 ] != 0 ) || ( data [ 14 ] != 1 ) || ( data [ 15 ] != 0x57 ) ) && ( data [ 21 ] & 32 ) ) {
var servertag = data [ 9 ] ;
var tag = ( serverid * 255 ) + servertag ;
var minorVersion = data [ 18 ] & 0x0F ;
var majorVersion = ( data [ 18 ] >> 4 ) & 0x0F ;
var provisioningState = data [ 19 ] & 0x03 ; // Pre = 0, In = 1, Post = 2
2018-08-30 03:40:30 +03:00
2017-08-28 19:27:45 +03:00
var openPort = ( data [ 16 ] * 256 ) + data [ 17 ] ;
var dualPorts = ( ( data [ 19 ] & 0x04 ) != 0 ) ? true : false ;
var openPorts = [ openPort ] ;
if ( dualPorts == true ) { openPorts = [ 16992 , 16993 ] ; }
if ( provisioningState <= 2 ) { func ( tag , minorVersion , majorVersion , provisioningState , openPort , dualPorts , rinfo , user ) ; }
}
2018-08-30 03:40:30 +03:00
} ;
2017-08-28 19:27:45 +03:00
// Use the RMCP packet to change the computer state
obj . changeConnectState = function ( tag , minorVersion , majorVersion , provisioningState , openPort , dualPorts , rinfo , user ) {
//var provisioningStates = { 0: 'Pre', 1: 'in', 2: 'Post' };
//var provisioningStateStr = provisioningStates[provisioningState];
2021-03-04 10:49:53 +03:00
//console.log('Intel AMT ' + majorVersion + '.' + minorVersion + ', ' + provisioningStateStr + '-Provisioning at ' + rinfo.address + ', Open Ports: [' + openPort + '], tag: ' + tag + ', dualPorts: ' + dualPorts);
2017-08-28 19:27:45 +03:00
var scaninfo = obj . scanTableTags [ tag ] ;
if ( scaninfo != undefined ) {
scaninfo . lastpong = Date . now ( ) ;
if ( scaninfo . state == 0 ) {
scaninfo . state = 1 ;
2021-03-04 10:49:53 +03:00
if ( ( openPort == 16993 ) || ( dualPorts == true ) ) { scaninfo . nodeinfo . intelamt . tls = 1 ; }
else if ( openPort == 16992 ) { scaninfo . nodeinfo . intelamt . tls = 0 ; }
if ( majorVersion > 0 ) { // Older versions of Intel AMT report the AMT version.
scaninfo . nodeinfo . intelamt . ver = majorVersion + '.' + minorVersion ;
scaninfo . nodeinfo . intelamt . state = provisioningState ;
}
2021-10-10 22:43:20 +03:00
obj . parent . SetConnectivityState ( scaninfo . nodeinfo . meshid , scaninfo . nodeinfo . _id , scaninfo . lastpong , 4 , 7 , null , { name : scaninfo . nodeinfo . name } ) ; // Report power state as "present" (7).
2017-08-28 19:27:45 +03:00
obj . changeAmtState ( scaninfo . nodeinfo . _id , scaninfo . nodeinfo . intelamt . ver , provisioningState , scaninfo . nodeinfo . intelamt . tls ) ;
2020-10-16 02:08:36 +03:00
if ( obj . parent . amtManager != null ) { obj . parent . amtManager . startAmtManagement ( scaninfo . nodeinfo . _id , 3 , scaninfo . nodeinfo . host ) ; }
2017-08-28 19:27:45 +03:00
}
}
2018-08-30 03:40:30 +03:00
} ;
2017-08-28 19:27:45 +03:00
2018-08-30 03:40:30 +03:00
// Use the RMCP packet to change the computer state
obj . reportMachineState = function ( tag , minorVersion , majorVersion , provisioningState , openPort , dualPorts , rinfo , user ) {
//var provisioningStates = { 0: 'Pre', 1: 'in', 2: 'Post' };
//var provisioningStateStr = provisioningStates[provisioningState];
//console.log(rinfo.address + ': Intel AMT ' + majorVersion + '.' + minorVersion + ', ' + provisioningStateStr + '-Provisioning, Open Ports: [' + openPorts.join(', ') + ']');
2020-04-20 13:22:33 +03:00
obj . dns . reverse ( rinfo . address , function ( err , hostnames ) {
if ( ( err == null ) && ( hostnames != null ) && ( hostnames . length > 0 ) ) {
2020-04-21 11:50:27 +03:00
user . results [ rinfo . address ] = { ver : majorVersion + '.' + minorVersion , tls : ( ( ( openPort == 16993 ) || ( dualPorts == true ) ) ? 1 : 0 ) , state : provisioningState , hostname : hostnames [ 0 ] , hosttype : 'host' } ;
2018-08-30 03:40:30 +03:00
} else {
2020-04-21 11:50:27 +03:00
user . results [ rinfo . address ] = { ver : majorVersion + '.' + minorVersion , tls : ( ( ( openPort == 16993 ) || ( dualPorts == true ) ) ? 1 : 0 ) , state : provisioningState , hostname : rinfo . address , hosttype : 'addr' } ;
2018-08-30 03:40:30 +03:00
}
} ) ;
} ;
2017-08-28 19:27:45 +03:00
// Change Intel AMT information in the database and event the changes
obj . changeAmtState = function ( nodeid , version , provisioningState , tls ) {
//console.log('changeAmtState', nodeid, version, provisioningState, tls);
obj . parent . db . Get ( nodeid , function ( err , nodes ) {
if ( nodes . length != 1 ) return ;
var node = nodes [ 0 ] ;
// Get the mesh for this device
obj . parent . db . Get ( node . meshid , function ( err , meshes ) {
if ( meshes . length != 1 ) return ;
var mesh = meshes [ 0 ] ;
// Ready the node change event
var changes = [ ] , event = { etype : 'node' , action : 'changenode' , nodeid : node . _id } ;
event . msg = + ": " ;
// Make the change & save
var change = false ;
if ( node . intelamt == undefined ) { node . intelamt = { } ; }
2018-08-30 03:40:30 +03:00
if ( node . intelamt . tls != tls ) { node . intelamt . tls = tls ; change = true ; changes . push ( tls == 1 ? 'TLS' : 'NoTLS' ) ; }
2018-05-01 23:44:26 +03:00
if ( obj . compareAmtVersionStr ( node . intelamt . ver , version ) ) { node . intelamt . ver = version ; change = true ; changes . push ( 'AMT Version ' + version ) ; }
if ( node . intelamt . state != provisioningState ) { node . intelamt . state = provisioningState ; change = true ; changes . push ( 'AMT State' ) ; }
2017-08-28 19:27:45 +03:00
if ( change == true ) {
// Make the change in the database
obj . parent . db . Set ( node ) ;
// Event the node change
event . msg = 'Intel® AMT changed device ' + node . name + ' from mesh ' + mesh . name + ': ' + changes . join ( ', ' ) ;
2019-10-11 21:16:36 +03:00
event . node = obj . parent . webserver . CloneSafeNode ( node ) ;
2019-05-29 03:25:23 +03:00
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.
2017-08-28 19:27:45 +03:00
obj . parent . DispatchEvent ( [ '*' , node . meshid ] , obj , event ) ;
}
} ) ;
} ) ;
2018-08-30 03:40:30 +03:00
} ;
2017-08-28 19:27:45 +03:00
// Return true if we should change the Intel AMT version number
obj . compareAmtVersionStr = function ( oldVer , newVer ) {
if ( oldVer == newVer ) return false ; // Versions are same already, don't update.
if ( newVer == undefined || newVer == null ) return false ; // New version is bad, don't update it.
if ( oldVer == undefined || oldVer == null ) return true ; // Old version is no good anyway, update it.
var oldVerArr = oldVer . split ( '.' ) ;
var newVerArr = newVer . split ( '.' ) ;
if ( ( oldVerArr . length < 2 ) || ( newVerArr . length < 2 ) ) return false ;
if ( ( oldVerArr [ 0 ] != newVerArr [ 0 ] ) || ( oldVerArr [ 1 ] != newVerArr [ 1 ] ) ) return true ;
if ( newVerArr . length > oldVerArr . length ) return true ;
if ( ( newVerArr . length == 3 ) && ( oldVerArr . length == 3 ) && ( oldVerArr [ 2 ] != newVerArr [ 2 ] ) ) return true ;
return false ;
2018-08-30 03:40:30 +03:00
} ;
2017-08-28 19:27:45 +03:00
2018-07-31 00:21:03 +03:00
// Check the presense of a specific Intel AMT computer using RMCP
2018-08-30 03:40:30 +03:00
obj . checkTcpPresence = function ( host , port , scaninfo , func ) { obj . ResolveName ( host , function ( hostname , ip ) { obj . checkTcpPresenceEx ( ip , port , scaninfo , func ) ; } ) ; } ;
2018-07-31 00:21:03 +03:00
2018-05-18 02:30:04 +03:00
// Check that we can connect TCP to a given port
2018-07-31 00:21:03 +03:00
obj . checkTcpPresenceEx = function ( host , port , scaninfo , func ) {
if ( host == null ) return ;
2018-05-18 02:30:04 +03:00
//console.log('checkTcpPresence(' + host + ':' + port + ')');
2018-05-19 03:29:25 +03:00
try {
var client ;
if ( port == 16992 ) {
// Connect using TCP
client = new obj . net . Socket ( ) ;
client . connect ( port , host , function ( ) { this . write ( 'GET / HTTP/1.1\r\nhost: ' + host + '\r\n\r\n' ) ; } ) ;
} else {
// 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.
if ( scaninfo . tlsoption == null ) { scaninfo . tlsoption = 0 ; }
2020-03-31 05:29:46 +03:00
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 } ;
if ( scaninfo . tlsoption == 1 ) { tlsOptions . secureProtocol = 'TLSv1_method' ; }
client = obj . tls . connect ( port , host , tlsOptions , function ( ) { this . write ( 'GET / HTTP/1.1\r\nhost: ' + host + '\r\n\r\n' ) ; } ) ;
2018-05-19 03:29:25 +03:00
}
client . scaninfo = scaninfo ;
client . func = func ;
client . port = port ;
client . setTimeout ( 10000 ) ;
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 ) ; } } ) ;
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 ) ; } } ) ;
client . on ( 'timeout' , function ( ) { if ( this . scaninfo . tcp != null ) { delete this . scaninfo . tcp ; try { this . destroy ( ) ; } catch ( ex ) { } this . func ( this . scaninfo , false ) ; } } ) ;
client . on ( 'close' , function ( ) { if ( this . scaninfo . tcp != null ) { delete this . scaninfo . tcp ; try { this . destroy ( ) ; } catch ( ex ) { } this . func ( this . scaninfo , false ) ; } } ) ;
client . on ( 'end' , function ( ) { if ( this . scaninfo . tcp != null ) { delete this . scaninfo . tcp ; try { this . destroy ( ) ; } catch ( ex ) { } this . func ( this . scaninfo , false ) ; } } ) ;
scaninfo . tcp = client ;
} catch ( ex ) { console . log ( ex ) ; }
2018-08-30 03:40:30 +03:00
} ;
2018-05-18 02:30:04 +03:00
2018-05-19 03:29:25 +03:00
// Return the Intel AMT version from the HTTP headers. Return null if nothing is found.
obj . getIntelAmtVersionFromHeaders = function ( headers ) {
if ( headers == null || headers . length == 0 ) return null ;
var lines = headers . split ( '\r\n' ) ;
for ( var i in lines ) {
// Look for the Intel AMT version
if ( lines [ i ] . substring ( 0 , 46 ) == 'Server: Intel(R) Active Management Technology ' ) {
// We need to check that the Intel AMT version is correct, in the "a.b.c" format
var ver = lines [ i ] . substring ( 46 ) , splitver = ver . split ( '.' ) ;
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 ] ) ; }
}
}
return null ;
2018-08-30 03:40:30 +03:00
} ;
2018-05-19 03:29:25 +03:00
//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"));
2017-08-28 19:27:45 +03:00
return obj ;
2018-08-30 03:40:30 +03:00
} ;