2017-08-28 19:27:45 +03:00
/ * *
* @ description Meshcentral Mesh Agent Local Scanner
* @ author Ylian Saint - Hilaire
* @ version v0 . 0.1
* /
// Construct a Mesh Scanner object
// TODO: We need once "server4" and "server6" per interface, or change the default multicast interface as we send.
module . exports . CreateMeshScanner = function ( parent ) {
var obj = { } ;
obj . parent = parent ;
obj . dgram = require ( 'dgram' ) ;
obj . common = require ( './common.js' ) ;
2017-09-01 23:45:25 +03:00
obj . servers4 = { } ;
obj . servers6 = { } ;
2017-08-28 19:27:45 +03:00
obj . mainTimer = null ;
var periodicScanTime = ( 60000 * 20 ) ; // Interval between scans, 20 minutes.
var membershipIPv4 = '239.255.255.235' ;
var membershipIPv6 = 'FF02:0:0:0:0:0:0:FE' ;
obj . agentCertificatHashHex = parent . certificateOperations . forge . pki . getPublicKeyFingerprint ( parent . certificateOperations . forge . pki . certificateFromPem ( parent . certificates . agent . cert ) . publicKey , { md : parent . certificateOperations . forge . md . sha256 . create ( ) , encoding : 'hex' } ) ;
obj . error = 0 ;
2017-09-01 23:45:25 +03:00
// Get a list of IPv4 and IPv6 interface addresses
function getInterfaceList ( ) {
var ipv4 = [ ] ;
var ipv6 = [ ] ;
var interfaces = require ( 'os' ) . networkInterfaces ( ) ;
for ( var i in interfaces ) {
var interface = interfaces [ i ] ;
for ( var j in interface ) {
var interface2 = interface [ j ] ;
if ( ( interface2 . mac != '00:00:00:00:00:00' ) && ( interface2 . internal == false ) ) {
if ( interface2 . family == 'IPv4' ) { ipv4 . push ( interface2 . address ) ; }
2017-09-06 03:19:28 +03:00
if ( interface2 . family == 'IPv6' ) { ipv6 . push ( interface2 . address + '%' + i ) ; }
2017-09-01 23:45:25 +03:00
}
}
}
return { ipv4 : ipv4 , ipv6 : ipv6 } ;
}
// Setup all IPv4 and IPv6 servers
function setupServers ( ) {
var addresses = getInterfaceList ( ) ;
for ( var i in obj . servers4 ) { obj . servers4 [ i ] . xxclear = true ; }
for ( var i in obj . servers6 ) { obj . servers6 [ i ] . xxclear = true ; }
for ( var i in addresses . ipv4 ) {
var localAddress = addresses . ipv4 [ i ] ;
if ( obj . servers4 [ localAddress ] != null ) {
// Server already exists
obj . servers4 [ localAddress ] . xxclear = false ;
} else {
// Create a new IPv4 server
var server4 = obj . dgram . createSocket ( "udp4" ) ;
server4 . xxclear = false ;
server4 . xxtype = 4 ;
server4 . xxlocal = localAddress ;
server4 . on ( 'error' , function ( err ) { console . log ( "ERROR: Server port " + server4 . xxlocal + ":16989 not available, check if server is running twice." ) ; server4 . close ( ) ; server4 = null ; } ) ;
server4 . bind ( { address : server4 . xxlocal , port : 16989 , exclusive : false } , function ( ) {
try {
server4 . setBroadcast ( true ) ;
server4 . setMulticastTTL ( 128 ) ;
server4 . addMembership ( membershipIPv4 ) ;
server4 . on ( 'error' , function ( error ) { console . log ( 'Error: ' + error ) ; } ) ;
server4 . on ( 'message' , function ( msg , info ) { onUdpPacket ( msg , info , server4 ) ; } ) ;
obj . performScan ( server4 ) ;
obj . performScan ( server4 ) ;
} catch ( e ) { }
} ) ;
obj . servers4 [ localAddress ] = server4 ;
}
}
for ( var i in addresses . ipv6 ) {
var localAddress = addresses . ipv6 [ i ] ;
if ( obj . servers6 [ localAddress ] != null ) {
// Server already exists
obj . servers6 [ localAddress ] . xxclear = false ;
} else {
// Create a new IPv6 server
var server6 = obj . dgram . createSocket ( "udp6" , localAddress ) ;
server6 . xxclear = false ;
server6 . xxtype = 6 ;
server6 . xxlocal = localAddress ;
2017-09-06 03:19:28 +03:00
server6 . on ( 'error' , function ( err ) { console . log ( "ERROR: Server port [" + server6 . xxlocal + "]:16989 not available, check if server is running twice." ) ; server6 . close ( ) ; obj . server6 = null ; } ) ;
2017-09-01 23:45:25 +03:00
server6 . bind ( { address : server6 . xxlocal , port : 16989 , exclusive : false } , function ( ) {
try {
server6 . setBroadcast ( true ) ;
server6 . setMulticastTTL ( 128 ) ;
server6 . addMembership ( membershipIPv6 ) ;
server6 . on ( 'error' , function ( error ) { console . log ( 'Error: ' + error ) ; } ) ;
server6 . on ( 'message' , function ( msg , info ) { onUdpPacket ( msg , info , server6 ) ; } ) ;
performScan ( server6 ) ;
performScan ( server6 ) ;
} catch ( e ) { }
} ) ;
obj . servers6 [ localAddress ] = server6 ;
}
}
for ( var i in obj . servers4 ) { if ( obj . servers4 [ i ] . xxclear == true ) { obj . servers4 [ i ] . close ( ) ; delete obj . servers4 [ i ] ; } ; }
for ( var i in obj . servers6 ) { if ( obj . servers6 [ i ] . xxclear == true ) { obj . servers6 [ i ] . close ( ) ; delete obj . servers6 [ i ] ; } ; }
}
// Clear all IPv4 and IPv6 servers
function clearServers ( ) {
for ( var i in obj . servers4 ) { obj . servers4 [ i ] . close ( ) ; delete obj . servers4 [ i ] ; }
for ( var i in obj . servers6 ) { obj . servers6 [ i ] . close ( ) ; delete obj . servers6 [ i ] ; }
}
2017-08-28 19:27:45 +03:00
// Start scanning for local network Mesh Agents
obj . start = function ( ) {
if ( obj . server4 != null ) return ;
var url = ( parent . args . notls ? 'ws' : 'wss' ) + '://%s:' + parent . args . port + '/agent.ashx' ;
obj . multicastPacket4 = Buffer . from ( "MeshCentral2|" + obj . agentCertificatHashHex . toUpperCase ( ) + '|' + url , 'ascii' ) ;
url = ( parent . args . notls ? 'ws' : 'wss' ) + '://[%s]:' + parent . args . port + '/agent.ashx' ;
obj . multicastPacket6 = Buffer . from ( "MeshCentral2|" + obj . agentCertificatHashHex . toUpperCase ( ) + '|' + url , 'ascii' ) ;
2017-09-01 23:45:25 +03:00
setupServers ( ) ;
2017-08-28 19:27:45 +03:00
obj . mainTimer = setInterval ( obj . performScan , periodicScanTime ) ;
return obj ;
}
// Stop scanning for local network Mesh Agents
obj . stop = function ( ) {
if ( obj . mainTimer != null ) { clearInterval ( obj . mainTimer ) ; obj . mainTimer = null ; }
2017-09-01 23:45:25 +03:00
clearServers ( ) ;
2017-08-28 19:27:45 +03:00
}
// Look for all Mesh Agents that may be locally reachable, indicating the presense of this server.
2017-09-01 23:45:25 +03:00
obj . performScan = function ( server ) {
if ( server != null ) {
if ( server . xxtype == 4 ) { server . send ( obj . multicastPacket4 , 0 , obj . multicastPacket4 . length , 16990 , membershipIPv4 ) ; }
if ( server . xxtype == 6 ) { server . send ( obj . multicastPacket6 , 0 , obj . multicastPacket6 . length , 16990 , membershipIPv6 ) ; }
} else {
for ( var i in obj . servers4 ) { obj . servers4 [ i ] . send ( obj . multicastPacket4 , 0 , obj . multicastPacket4 . length , 16990 , membershipIPv4 ) ; }
for ( var i in obj . servers6 ) { obj . servers6 [ i ] . send ( obj . multicastPacket6 , 0 , obj . multicastPacket6 . length , 16990 , membershipIPv6 ) ; }
setupServers ( ) ; // Check if any network interfaces where added or removed
}
2017-08-28 19:27:45 +03:00
}
// Called when a UDP packet is received from an agent.
2017-09-01 23:45:25 +03:00
function onUdpPacket ( msg , info , server ) {
// console.log('Received ' + msg.length + ' bytes from ' + info.address + ':' + info.port + ', on interface: ' + server.xxlocal + '.');
2017-08-28 19:27:45 +03:00
if ( ( msg . length == 64 ) && ( msg . toString ( 'ascii' ) == obj . agentCertificatHashHex . toUpperCase ( ) ) ) {
2017-09-01 23:45:25 +03:00
if ( server . xxtype == 4 ) { server . send ( obj . multicastPacket4 , 0 , obj . multicastPacket4 . length , info . port , info . address ) ; }
if ( server . xxtype == 6 ) { server . send ( obj . multicastPacket6 , 0 , obj . multicastPacket6 . length , info . port , info . address ) ; }
2017-08-28 19:27:45 +03:00
}
}
// As a side job, we also send server wake-on-lan packets
obj . wakeOnLan = function ( macs ) {
for ( var i in macs ) {
var mac = macs [ i ] ;
var hexpacket = 'FFFFFFFFFFFF' ;
for ( var i = 0 ; i < 16 ; i ++ ) { hexpacket += mac ; }
var wakepacket = Buffer . from ( hexpacket , 'hex' ) ;
//console.log(wakepacket.toString('hex'));
// Send the wake packet 3 times with small time intervals
2017-09-01 23:45:25 +03:00
for ( var i in obj . servers4 ) { obj . servers4 [ i ] . send ( wakepacket , 0 , wakepacket . length , 7 , "255.255.255.255" ) ; obj . servers4 [ i ] . send ( wakepacket , 0 , wakepacket . length , 16990 , membershipIPv4 ) ; }
for ( var i in obj . servers6 ) { obj . servers6 [ i ] . send ( wakepacket , 0 , wakepacket . length , 16990 , membershipIPv6 ) ; }
2017-08-28 19:27:45 +03:00
setTimeout ( function ( ) {
2017-09-01 23:45:25 +03:00
for ( var i in obj . servers4 ) { obj . servers4 [ i ] . send ( wakepacket , 0 , wakepacket . length , 7 , "255.255.255.255" ) ; obj . servers4 [ i ] . send ( wakepacket , 0 , wakepacket . length , 16990 , membershipIPv4 ) ; }
for ( var i in obj . servers6 ) { obj . servers6 [ i ] . send ( wakepacket , 0 , wakepacket . length , 16990 , membershipIPv6 ) ; }
2017-08-28 19:27:45 +03:00
} , 200 ) ;
setTimeout ( function ( ) {
2017-09-01 23:45:25 +03:00
for ( var i in obj . servers4 ) { obj . servers4 [ i ] . send ( wakepacket , 0 , wakepacket . length , 7 , "255.255.255.255" ) ; obj . servers4 [ i ] . send ( wakepacket , 0 , wakepacket . length , 16990 , membershipIPv4 ) ; }
for ( var i in obj . servers6 ) { obj . servers6 [ i ] . send ( wakepacket , 0 , wakepacket . length , 16990 , membershipIPv6 ) ; }
2017-08-28 19:27:45 +03:00
} , 500 ) ;
}
}
return obj ;
}