2017-08-28 12:27:45 -04: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 16:45:25 -04:00
obj . servers4 = { } ;
obj . servers6 = { } ;
2017-08-28 12:27:45 -04: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' ;
2017-10-18 19:28:05 -04:00
obj . agentCertificateHashHex = parent . certificateOperations . forge . pki . getPublicKeyFingerprint ( parent . certificateOperations . forge . pki . certificateFromPem ( parent . certificates . agent . cert ) . publicKey , { md : parent . certificateOperations . forge . md . sha384 . create ( ) , encoding : 'hex' } ) . toUpperCase ( ) ;
2017-08-28 12:27:45 -04:00
obj . error = 0 ;
2017-09-01 16:45:25 -04:00
// Get a list of IPv4 and IPv6 interface addresses
function getInterfaceList ( ) {
2017-10-15 02:22:19 -04:00
var ipv4 = [ '*' ] , ipv6 = [ '*' ] ; // Bind to IN_ADDR_ANY always
2017-10-18 19:28:05 -04:00
//if (parent.platform == 'win32') { // On Windows, also bind to each interface seperatly (TODO: REMOVE THIS AND TEST ON LINUX!!!!!!!!!!!!!!!!!!)
2017-10-15 02:22:19 -04:00
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 ) ; }
if ( interface2 . family == 'IPv6' ) { ipv6 . push ( interface2 . address + '%' + i ) ; }
}
2017-09-01 16:45:25 -04:00
}
}
2017-10-18 19:28:05 -04:00
//}
2017-09-01 16:45:25 -04: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
2017-10-02 17:12:29 -04:00
try {
2017-10-18 19:28:05 -04:00
var server4 = obj . dgram . createSocket ( { type : 'udp4' , reuseAddr : true } ) ;
2017-10-02 17:12:29 -04:00
server4 . xxclear = false ;
server4 . xxtype = 4 ;
server4 . xxlocal = localAddress ;
2017-10-03 21:31:20 -04:00
server4 . on ( 'error' , function ( err ) { if ( this . xxlocal == '*' ) { console . log ( "ERROR: Server port 16989 not available, check if server is running twice." ) ; } this . close ( ) ; delete obj . servers6 [ this . xxlocal ] ; } ) ;
2017-10-02 17:12:29 -04:00
var bindOptions = { port : 16989 , exclusive : false } ;
if ( server4 . xxlocal != '*' ) { bindOptions . address = server4 . xxlocal ; }
server4 . bind ( bindOptions , function ( ) {
try {
this . setBroadcast ( true ) ;
this . setMulticastTTL ( 128 ) ;
this . addMembership ( membershipIPv4 ) ;
2017-10-18 19:28:05 -04:00
this . on ( 'error' , function ( error ) { console . log ( 'Error: ' + error ) ; } ) ;
this . on ( 'message' , function ( msg , info ) { onUdpPacket ( msg , info , this ) ; } ) ;
2017-10-02 17:12:29 -04:00
obj . performScan ( this ) ;
obj . performScan ( this ) ;
} catch ( e ) { }
} ) ;
obj . servers4 [ localAddress ] = server4 ;
} catch ( e ) {
console . log ( e ) ;
}
2017-09-01 16:45:25 -04:00
}
}
2017-10-02 17:12:29 -04:00
2017-09-01 16:45:25 -04:00
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
2017-10-18 19:28:05 -04:00
var server6 = obj . dgram . createSocket ( { type : 'udp6' , reuseAddr : true } ) ;
2017-09-01 16:45:25 -04:00
server6 . xxclear = false ;
server6 . xxtype = 6 ;
server6 . xxlocal = localAddress ;
2017-10-03 21:31:20 -04:00
server6 . on ( 'error' , function ( err ) { this . close ( ) ; delete obj . servers6 [ this . xxlocal ] ; } ) ;
2017-10-02 17:12:29 -04:00
var bindOptions = { port : 16989 , exclusive : false } ;
if ( server6 . xxlocal != '*' ) { bindOptions . address = server6 . xxlocal ; }
server6 . bind ( bindOptions , function ( ) {
2017-09-01 16:45:25 -04:00
try {
2017-10-02 17:12:29 -04:00
this . setBroadcast ( true ) ;
this . setMulticastTTL ( 128 ) ;
this . addMembership ( membershipIPv6 ) ;
this . on ( 'error' , function ( error ) { console . log ( 'Error: ' + error ) ; } ) ;
this . on ( 'message' , function ( msg , info ) { onUdpPacket ( msg , info , this ) ; } ) ;
obj . performScan ( this ) ;
obj . performScan ( this ) ;
2017-09-01 16:45:25 -04:00
} catch ( e ) { }
} ) ;
obj . servers6 [ localAddress ] = server6 ;
}
}
2017-10-18 19:28:05 -04:00
2017-09-01 16:45:25 -04:00
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 12:27:45 -04: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' ;
2017-10-18 19:28:05 -04:00
obj . multicastPacket4 = Buffer . from ( "MeshCentral2|" + obj . agentCertificateHashHex + '|' + url , 'ascii' ) ;
2017-08-28 12:27:45 -04:00
url = ( parent . args . notls ? 'ws' : 'wss' ) + '://[%s]:' + parent . args . port + '/agent.ashx' ;
2017-10-18 19:28:05 -04:00
obj . multicastPacket6 = Buffer . from ( "MeshCentral2|" + obj . agentCertificateHashHex + '|' + url , 'ascii' ) ;
2017-09-01 16:45:25 -04:00
setupServers ( ) ;
2017-08-28 12:27:45 -04: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 16:45:25 -04:00
clearServers ( ) ;
2017-08-28 12:27:45 -04:00
}
// Look for all Mesh Agents that may be locally reachable, indicating the presense of this server.
2017-09-01 16:45:25 -04:00
obj . performScan = function ( server ) {
if ( server != null ) {
2017-10-04 18:53:52 -04:00
if ( server . xxtype == 4 ) { try { server . send ( obj . multicastPacket4 , 0 , obj . multicastPacket4 . length , 16990 , membershipIPv4 ) ; } catch ( e ) { } }
if ( server . xxtype == 6 ) { try { server . send ( obj . multicastPacket6 , 0 , obj . multicastPacket6 . length , 16990 , membershipIPv6 ) ; } catch ( e ) { } }
if ( ( server . xxtype == 4 ) && ( server . xxlocal == '*' ) ) { try { server . send ( obj . multicastPacket4 , 0 , obj . multicastPacket4 . length , 16990 , '127.0.0.1' ) ; } catch ( e ) { } try { server . send ( obj . multicastPacket4 , 0 , obj . multicastPacket4 . length , 16990 , '255.255.255.255' ) ; } catch ( e ) { } }
if ( ( server . xxtype == 6 ) && ( server . xxlocal == '*' ) ) { try { server . send ( obj . multicastPacket6 , 0 , obj . multicastPacket6 . length , 16990 , '::1' ) ; } catch ( e ) { } }
2017-09-01 16:45:25 -04:00
} else {
2017-10-04 18:53:52 -04:00
for ( var i in obj . servers4 ) { try { obj . servers4 [ i ] . send ( obj . multicastPacket4 , 0 , obj . multicastPacket4 . length , 16990 , membershipIPv4 ) ; } catch ( e ) { } }
for ( var i in obj . servers6 ) { try { obj . servers6 [ i ] . send ( obj . multicastPacket6 , 0 , obj . multicastPacket6 . length , 16990 , membershipIPv6 ) ; } catch ( e ) { } }
2017-09-01 16:45:25 -04:00
setupServers ( ) ; // Check if any network interfaces where added or removed
}
2017-08-28 12:27:45 -04:00
}
// Called when a UDP packet is received from an agent.
2017-09-01 16:45:25 -04:00
function onUdpPacket ( msg , info , server ) {
2017-10-02 17:12:29 -04:00
//console.log('Received ' + msg.length + ' bytes from ' + info.address + ':' + info.port + ', on interface: ' + server.xxlocal + '.');
2017-10-18 19:28:05 -04:00
if ( ( msg . length == 96 ) && ( msg . toString ( 'ascii' ) == obj . agentCertificateHashHex ) ) {
2017-10-04 18:53:52 -04:00
if ( server . xxtype == 4 ) { try { server . send ( obj . multicastPacket4 , 0 , obj . multicastPacket4 . length , info . port , info . address ) ; } catch ( e ) { } }
if ( server . xxtype == 6 ) { try { server . send ( obj . multicastPacket6 , 0 , obj . multicastPacket6 . length , info . port , info . address ) ; } catch ( e ) { } }
2017-08-28 12:27:45 -04: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 16:45:25 -04: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 12:27:45 -04:00
setTimeout ( function ( ) {
2017-09-01 16:45:25 -04: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 12:27:45 -04:00
} , 200 ) ;
setTimeout ( function ( ) {
2017-09-01 16:45:25 -04: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 12:27:45 -04:00
} , 500 ) ;
}
}
return obj ;
}