2017-11-03 20:01:30 -04:00
/ * *
2018-01-04 15:15:21 -05:00
* @ description MeshCentral v1 legacy Swarm Server , used to update agents and get them on MeshCentral2
2017-11-03 20:01:30 -04:00
* @ author Ylian Saint - Hilaire
2020-01-02 21:30:12 -05:00
* @ copyright Intel Corporation 2018 - 2020
2018-01-04 15:15:21 -05:00
* @ license Apache - 2.0
2017-11-03 20:01:30 -04:00
* @ version v0 . 0.1
* /
2018-08-30 15:05:23 -04:00
/*jslint node: true */
/*jshint node: true */
/*jshint strict:false */
/*jshint -W097 */
/*jshint esversion: 6 */
"use strict" ;
2018-08-27 15:24:15 -04:00
2017-11-03 20:01:30 -04:00
// Construct a legacy Swarm Server server object
module . exports . CreateSwarmServer = function ( parent , db , args , certificates ) {
var obj = { } ;
obj . parent = parent ;
obj . db = db ;
obj . args = args ;
obj . certificates = certificates ;
2017-11-06 20:54:40 -05:00
obj . legacyAgentConnections = { } ;
obj . migrationAgents = { } ;
2019-01-22 14:44:46 -05:00
obj . agentActionCount = { } ;
2019-03-07 22:56:24 -05:00
obj . stats = { blockedConnect : 0 , connectCount : 0 , clientCertConnectCount : 0 , noCertConnectCount : 0 , bytesIn : 0 , bytesOut : 0 , httpGetRequest : 0 , pushedAgents : { } , close : 0 , onclose : 0 , agentType : { } }
2018-05-03 14:09:29 -04:00
const tls = require ( 'tls' ) ;
const forge = require ( 'node-forge' ) ;
2019-02-27 21:48:50 -05:00
const common = require ( './common.js' ) ;
2017-11-03 20:01:30 -04:00
2018-05-03 14:09:29 -04:00
const LegacyMeshProtocol = {
2017-11-03 20:01:30 -04:00
NODEPUSH : 1 , // Used to send a node block to another peer.
NODEPULL : 2 , // Used to send a pull block to another peer.
NODENOTIFY : 3 , // Used to indicate the node ID to other peers.
NODECHALLENGE : 4 , // Used to challenge a node identity.
NODECRESPONSE : 5 , // Used to respond to a node challenge.
TARGETSTATUS : 6 , // Used to send the peer connection status list.
LOCALEVENT : 7 , // Used to send local events to subscribers.
AESCRYPTO : 8 , // Used to send an encrypted block of data.
SESSIONKEY : 9 , // Used to send a session key to a remote node.
SYNCSTART : 10 , // Used to send kick off the SYNC request, send the start NodeID.
SYNCMETADATA : 11 , // Used to send a sequence of NodeID & serial numbers.
SYNCREQUEST : 12 , // Used to send a sequence of NodeID's to request.
NODEID : 13 , // Used to send the NodeID in the clear. Used for multicast.
AGENTID : 14 , // Used to send the AgentID & version to the other node.
PING : 15 , // Used to query a target for the presence of the mesh agent (PB_NODEID response expected).
SETUPADMIN : 16 , // Used to set the trusted mesh identifier, this code can only be used from local settings file.
POLICY : 17 , // Used to send a policy block to another peer.
POLICYSECRET : 18 , // Used to encode the PKCS12 private key of a policy block.
EVENTMASK : 19 , // Used by the mesh service to change the event mask.
RECONNECT : 20 , // Used by the mesh service to indicate disconnect & reconnection after n seconds.
GETSTATE : 21 , // Used by the mesh service to obtain agent state.
CERTENCRYPTED : 22 , // Used to send a certificate encrypted message to a node.
GETCOOKIE : 23 , // Used to request a certificate encryption anti-replay cookie.
COOKIE : 24 , // Used to carry an anti-replay cookie to a requestor.
SESSIONCKEY : 25 , // Used to send a session key to a remote console.
INTERFACE : 26 , // Used to send a local interface blob to a management console.
MULTICAST : 27 , // Used by the mesh service to cause the agent to send a multicast.
SELFEXE : 28 , // Used to transfer our own agent executable.
LEADERBADGE : 29 , // User to send a leadership badge.
NODEINFO : 30 , // Used to indicate a block information update to the web service.
TARGETEVENT : 31 , // Used to send a single target update event.
DEBUG : 33 , // Used to send debug information to web service.
TCPRELAY : 34 , // Used to operate mesh leader TCP relay sockets
CERTSIGNED : 35 , // Used to send a certificate signed message to a node.
ERRORCODE : 36 , // Used to notify of an error.
MESSAGE : 37 , // Used to route messages between nodes.
CMESSAGE : 38 , // Used to embed a interface identifier along with a PB_MESSAGE.
EMESSAGE : 39 , // Used to embed a target encryption certificate along with a MESSAGE or CMESSAGE.
SEARCH : 40 , // Used to send a custom search to one or more remote nodes.
MESSAGERELAY : 41 , // Used by no-certificate consoles to send hopping messages to nodes.
USERINPUT : 42 , // Used to send user keyboard input to a target computer
APPID : 43 , // Used to send a block of data to a specific application identifier.
APPSUBSCRIBE : 44 , // Used to perform local app subscription to an agent.
APPDIRECT : 45 , // Used to send message directly to remote applications.
APPREQACK : 46 , // Used to request an ack message.
APPACK : 47 , // Used to ack a received message.
SERVERECHO : 48 , // Server will echo this message, used for testing.
KVMINFO : 49 , // Used to send local KVM slave process information to mesh agent.
REMOTEWAKE : 50 , // Used to send remote wake information to server.
NEWCONNECTTOKEN : 51 , // Used to send a new connection token to the Swarm Server.
WIFISCAN : 52 , // Used to send visible WIFI AP's to the server.
AMTPROVISIONING : 53 , // Used by the agent to send Intel AMT provisioning information to the server.
ANDROIDCOMMAND : 54 , // Send a Android OS specific command (Android only).
NODEAPPDATA : 55 , // Used to send application specific data block to the server for storage.
PROXY : 56 , // Used to indicate the currently used proxy setting string.
FILEOPERATION : 57 , // Used to perform short file operations.
APPSUBSCRIBERS : 58 , // Used request and send to the mesh server the list of subscribed applications
CUSTOM : 100 , // Message containing application specific data.
USERAUTH : 1000 , // Authenticate a user to the swarm server.
USERMESH : 1001 , // Request or return the mesh list for this console.
USERMESHS : 1002 , // Send mesh overview information to the console.
USERNODES : 1003 , // Send node overview information to the console.
JUSERMESHS : 1004 , // Send mesh overview information to the console in JSON format.
JUSERNODES : 1005 , // Send node overview information to the console in JSON format.
USERPOWERSTATE : 1006 , // Used to send a power command from the console to the server.
JMESHPOWERTIMELINE : 1007 , // Send the power timeline for all nodes in a mesh.
JMESHPOWERSUMMARY : 1008 , // Send the power summary for sum of all nodes in a mesh.
USERCOMMAND : 1009 , // Send a user admin text command to and from the server.
POWERBLOCK : 1010 , // Request/Response of block of power state information.
MESHACCESSCHANGE : 1011 , // Notify a console of a change in accessible meshes.
COOKIEAUTH : 1012 , // Authenticate a user using a crypto cookie.
NODESTATECHANGE : 1013 , // Indicates a node has changed power state.
JUSERNODE : 1014 , // Send node overview information to the console in JSON format.
AMTWSMANEVENT : 1015 , // Intel AMT WSMAN event sent to consoles.
ROUTINGCOOKIE : 1016 , // Used by a console to request a routing cookie.
JCOLLABORATION : 1017 , // Request/send back JSON collaboration state.
JRELATIONS : 1018 , // Request/send back JSON relations state.
SETCOLLABSTATE : 1019 , // Set the collaboration state for this session.
ADDRELATION : 1020 , // Request that a new relation be added.
DELETERELATION : 1021 , // Request a relation be deleted.
ACCEPTRELATION : 1022 , // Request relation invitation be accepted.
RELATIONCHANGEEVENT : 1023 , // Notify that a relation has changed.
COLLBCHANGEEVENT : 1024 , // Notify that a collaboration state has change.
MULTICONSOLEMESSAGE : 1025 , // Send a message to one or more console id's.
CONSOLEID : 1026 , // Notify a console of it's console id.
CHANGERELATIONDATA : 1027 , // Request that relation data be changed.
SETUSERDATA : 1028 , // Set user data
GETUSERDATA : 1029 , // Get user data
SERVERAUTH : 1030 , // Used to verify the certificate of the server
USERAUTH2 : 1031 , // Authenticate a user to the swarm server (Uses SHA1 SALT)
GUESTREMOTEDESKTOP : 2001 , // Guest usage: Remote Desktop
GUESTWEBRTCMESH : 2002 // Guest usage: WebRTC Mesh
2018-08-30 15:05:23 -04:00
} ;
2017-11-03 20:01:30 -04:00
2019-01-11 13:02:54 -05:00
obj . server = tls . createServer ( { key : certificates . swarmserver . key , cert : certificates . swarmserver . cert , requestCert : true , rejectUnauthorized : false } , onConnection ) ;
2018-03-14 15:10:13 -04:00
obj . server . listen ( args . swarmport , function ( ) { console . log ( 'MeshCentral Legacy Swarm Server running on ' + certificates . CommonName + ':' + args . swarmport + '.' ) ; obj . parent . updateServerState ( 'swarm-port' , args . swarmport ) ; } ) . on ( 'error' , function ( err ) { console . error ( 'ERROR: MeshCentral Swarm Server server port ' + args . swarmport + ' is not available.' ) ; if ( args . exactports ) { process . exit ( ) ; } } ) ;
2017-11-06 20:54:40 -05:00
loadMigrationAgents ( ) ;
// Load all migration agents along with full executable in memory
function loadMigrationAgents ( ) {
var migrationAgentsDir = null , migrationAgentsPath = obj . parent . path . join ( obj . parent . datapath , 'migrationagents' ) ;
try { migrationAgentsDir = obj . parent . fs . readdirSync ( migrationAgentsPath ) ; } catch ( e ) { }
if ( migrationAgentsDir != null ) {
for ( var i in migrationAgentsDir ) {
if ( migrationAgentsDir [ i ] . toLowerCase ( ) . startsWith ( 'meshagent-' ) ) {
var migrationAgentName = obj . parent . path . join ( migrationAgentsPath , migrationAgentsDir [ i ] ) ;
var agentInfo = migrationAgentsDir [ i ] . substring ( 10 ) . split ( '.' ) ;
var agentVersion = parseInt ( agentInfo [ 0 ] ) ;
var agentArch = parseInt ( agentInfo [ 1 ] ) ;
if ( obj . migrationAgents [ agentArch ] == null ) { obj . migrationAgents [ agentArch ] = { } ; }
2019-03-08 01:47:27 -05:00
if ( obj . migrationAgents [ agentArch ] [ agentVersion ] == null ) { obj . migrationAgents [ agentArch ] [ agentVersion ] = { arch : agentArch , ver : agentVersion , path : migrationAgentName } ; }
2017-11-06 20:54:40 -05:00
}
}
}
}
2019-03-06 12:15:32 -05:00
function onData ( data ) {
if ( this . relaySocket ) { var ps = this ; try { this . relaySocket . write ( data , 'binary' , function ( ) { ps . resume ( ) ; } ) ; } catch ( ex ) { } return ; }
if ( args . swarmdebug ) { var buf = Buffer . from ( data , "binary" ) ; console . log ( 'SWARM <-- (' + buf . length + '):' + buf . toString ( 'hex' ) ) ; } // Print out received bytes
obj . stats . bytesIn += data . length ;
this . tag . accumulator += data ;
2019-01-11 13:02:54 -05:00
2019-03-06 12:15:32 -05:00
// Detect if this is an HTTPS request, if it is, return a simple answer and disconnect. This is useful for debugging access to the MPS port.
if ( this . tag . first == true ) {
if ( this . tag . accumulator . length < 3 ) return ;
if ( ( this . tag . accumulator . substring ( 0 , 3 ) == 'GET' ) || ( this . tag . accumulator . substring ( 0 , 3 ) == 'POS' ) ) {
obj . stats . httpGetRequest ++ ;
/*console.log("Swarm Connection, HTTP GET detected: " + socket.remoteAddress);*/
//socket.write('HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body>MeshCentral2 legacy swarm server.<br />MeshCentral1 mesh agents should connect here for updates.</body></html>');
//socket.end();
2017-11-03 20:01:30 -04:00
2019-03-06 12:15:32 -05:00
// Relay this connection to the main TLS port
this . pause ( ) ;
var relaySocket = tls . connect ( obj . args . port , { rejectUnauthorized : false } , function ( ) { this . write ( this . parentSocket . tag . accumulator ) ; this . parentSocket . resume ( ) ; } ) ;
relaySocket . on ( 'data' , function ( data ) { try { var rs = this ; this . pause ( ) ; this . parentSocket . write ( data , 'binary' , function ( ) { rs . resume ( ) ; } ) ; } catch ( ex ) { } } ) ;
relaySocket . on ( 'error' , function ( err ) { try { this . parentSocket . end ( ) ; } catch ( ex ) { } } ) ;
relaySocket . on ( 'end' , function ( ) { try { this . parentSocket . end ( ) ; } catch ( ex ) { } } ) ;
this . relaySocket = relaySocket ;
relaySocket . parentSocket = this ;
2019-02-27 21:48:50 -05:00
return ;
}
2019-03-06 12:15:32 -05:00
this . tag . first = false ;
}
2017-11-03 20:01:30 -04:00
2019-03-06 12:15:32 -05:00
// A client certificate is required
if ( ( this . tag . clientCert == null ) || ( this . tag . clientCert . subject == null ) ) {
/*console.log("Swarm Connection, no client cert: " + socket.remoteAddress);*/
this . write ( 'HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nMeshCentral2 legacy swarm server.\r\nNo client certificate given.' ) ;
2019-03-07 22:56:24 -05:00
//this.end(); // If we don't close the connection, it may lead to less reconnection traffic.
2019-03-06 12:15:32 -05:00
return ;
}
2017-11-03 20:01:30 -04:00
2019-03-06 12:15:32 -05:00
try {
// Parse all of the agent binary command data we can
var l = 0 ;
do { l = ProcessCommand ( this ) ; if ( l > 0 ) { this . tag . accumulator = this . tag . accumulator . substring ( l ) ; } } while ( l > 0 ) ;
if ( l < 0 ) { this . end ( ) ; }
} catch ( e ) {
console . log ( e ) ;
}
}
2017-11-03 20:01:30 -04:00
2019-03-06 12:15:32 -05:00
// Process one AFP command
function ProcessCommand ( socket ) {
if ( socket . tag . accumulator . length < 4 ) return 0 ;
var cmd = common . ReadShort ( socket . tag . accumulator , 0 ) ;
var len = common . ReadShort ( socket . tag . accumulator , 2 ) ;
if ( len > socket . tag . accumulator . length ) return 0 ;
var data = socket . tag . accumulator . substring ( 4 , len ) ;
//console.log('Swarm: Cmd=' + cmd + ', Len=' + len + '.');
2017-11-06 20:54:40 -05:00
2019-03-06 12:15:32 -05:00
switch ( cmd ) {
case LegacyMeshProtocol . NODEPUSH : {
2019-08-22 18:31:39 -04:00
parent . debug ( 'swarmcmd' , 'NODEPUSH' ) ;
2019-03-06 12:15:32 -05:00
var nodeblock = obj . decodeNodeBlock ( data ) ;
if ( ( nodeblock != null ) && ( nodeblock . agenttype != null ) && ( nodeblock . agentversion != null ) ) {
if ( socket . pingTimer == null ) { socket . pingTimer = setInterval ( function ( ) { obj . SendCommand ( socket , LegacyMeshProtocol . PING ) ; } , 20000 ) ; }
2019-08-22 18:31:39 -04:00
parent . debug ( 'swarmcmd' , 'NODEPUSH:' + JSON . stringify ( nodeblock ) ) ;
2019-01-22 14:44:46 -05:00
2019-03-07 22:56:24 -05:00
// Log the agent type
if ( obj . stats . agenttype [ nodeblock . agenttype ] == null ) { obj . stats . agenttype [ nodeblock . agenttype ] = 1 ; } else { obj . stats . agenttype [ nodeblock . agenttype ] ++ ; }
2019-03-06 12:15:32 -05:00
// Check if this agent is asking of updates over and over again.
var actionCount = obj . agentActionCount [ nodeblock . nodeidhex ] ;
if ( actionCount == null ) { actionCount = 0 ; }
if ( actionCount > 2 ) {
// Already tried to update this agent two times, something is not right.
//console.log('SWARM: ' + actionCount + ' update actions on ' + nodeblock.nodeidhex + ', holding.');
} else {
// Figure out what is the next agent version we need.
var nextAgentVersion = 0 ;
if ( nodeblock . agentversion < 201 ) { nextAgentVersion = 201 ; } // If less then 201, move to transitional MC1 agent.
if ( nodeblock . agentversion == 201 ) { nextAgentVersion = 202 ; } // If at 201, move to first MC2 agent.
2019-01-28 19:53:11 -05:00
2019-03-06 12:15:32 -05:00
// See if we need to start the agent update
if ( ( nextAgentVersion > 0 ) && ( obj . migrationAgents [ nodeblock . agenttype ] != null ) && ( obj . migrationAgents [ nodeblock . agenttype ] [ nextAgentVersion ] != null ) ) {
// Start the update
socket . tag . update = obj . migrationAgents [ nodeblock . agenttype ] [ nextAgentVersion ] ;
socket . tag . updatePtr = 0 ;
//console.log('Performing legacy agent update from ' + nodeblock.agentversion + '.' + nodeblock.agenttype + ' to ' + socket.tag.update.ver + '.' + socket.tag.update.arch + ' on ' + nodeblock.agentname + '.');
2019-02-27 21:48:50 -05:00
2019-03-06 12:15:32 -05:00
// Update stats
if ( obj . stats . pushedAgents [ nodeblock . agenttype ] == null ) { obj . stats . pushedAgents [ nodeblock . agenttype ] = { } ; }
2019-03-07 22:56:24 -05:00
if ( obj . stats . pushedAgents [ nodeblock . agenttype ] [ nextAgentVersion ] == null ) { obj . stats . pushedAgents [ nodeblock . agenttype ] [ nextAgentVersion ] = 1 ; } else { obj . stats . pushedAgents [ nodeblock . agenttype ] [ nextAgentVersion ] ++ ; }
2019-01-22 14:44:46 -05:00
2019-03-06 12:15:32 -05:00
// Start the agent download using the task limiter so not to flood the server. Low priority task
obj . parent . taskLimiter . launch ( function ( socket , taskid , taskLimiterQueue ) {
if ( socket . xclosed == 1 ) {
// Socket is closed, do nothing
obj . parent . taskLimiter . completed ( taskid ) ; // Indicate this task complete
} else {
// Start the agent update
socket . tag . taskid = taskid ;
obj . SendCommand ( socket , LegacyMeshProtocol . GETSTATE , common . IntToStr ( 5 ) + common . IntToStr ( 0 ) ) ; // agent.SendQuery(5, 0); // Start the agent download
}
} , socket , 2 ) ;
} else {
//console.log('No legacy agent update for ' + nodeblock.agentversion + '.' + nodeblock.agenttype + ' on ' + nodeblock.agentname + '.');
}
2017-11-06 20:54:40 -05:00
}
2019-03-06 12:15:32 -05:00
// Mark this agent
obj . agentActionCount [ nodeblock . nodeidhex ] = ++ actionCount ;
2017-11-06 20:54:40 -05:00
}
2019-03-06 12:15:32 -05:00
break ;
}
case LegacyMeshProtocol . AMTPROVISIONING : {
2019-08-22 18:31:39 -04:00
parent . debug ( 'swarmcmd' , 'AMTPROVISIONING' ) ;
2019-03-06 12:15:32 -05:00
obj . SendCommand ( socket , LegacyMeshProtocol . AMTPROVISIONING , common . ShortToStr ( 1 ) ) ;
break ;
}
case LegacyMeshProtocol . GETSTATE : {
2019-08-22 18:31:39 -04:00
parent . debug ( 'swarmcmd' , 'GETSTATE' ) ;
2019-03-06 12:15:32 -05:00
if ( len < 12 ) break ;
var statecmd = common . ReadInt ( data , 0 ) ;
//var statesync = common.ReadInt(data, 4);
switch ( statecmd ) {
case 6 : { // Ask for agent block
if ( socket . tag . update != null ) {
// Send an agent block
2019-03-08 01:47:27 -05:00
if ( socket . tag . update . binary == null ) { socket . tag . update . binary = obj . parent . fs . readFileSync ( socket . tag . update . path ) ; }
2019-03-06 12:15:32 -05:00
var l = Math . min ( socket . tag . update . binary . length - socket . tag . updatePtr , 16384 ) ;
obj . SendCommand ( socket , LegacyMeshProtocol . GETSTATE , common . IntToStr ( 6 ) + common . IntToStr ( socket . tag . updatePtr ) + socket . tag . update . binary . toString ( 'binary' , socket . tag . updatePtr , socket . tag . updatePtr + l ) ) ; // agent.SendQuery(6, AgentFileLen + AgentBlock);
2019-08-22 18:31:39 -04:00
parent . debug ( 'swarmcmd' , 'Sending agent block, ptr = ' + socket . tag . updatePtr + ', len = ' + l ) ;
2017-11-06 20:54:40 -05:00
2019-03-06 12:15:32 -05:00
socket . tag . updatePtr += l ;
if ( socket . tag . updatePtr >= socket . tag . update . binary . length ) {
// Send end-of-transfer
obj . SendCommand ( socket , LegacyMeshProtocol . GETSTATE , common . IntToStr ( 7 ) + common . IntToStr ( socket . tag . update . binary . length ) ) ; //agent.SendQuery(7, AgentFileLen);
2019-08-22 18:31:39 -04:00
parent . debug ( ' swarmcmd ', ' Sending end of agent , ptr = ' + socket . tag . updatePtr ) ;
2019-03-06 12:15:32 -05:00
obj . parent . taskLimiter . completed ( socket . tag . taskid ) ; // Indicate this task complete
delete socket . tag . taskid ;
delete socket . tag . update ;
delete socket . tag . updatePtr ;
2017-11-06 20:54:40 -05:00
}
2019-01-04 20:59:13 -05:00
}
2019-03-06 12:15:32 -05:00
break ;
}
default : {
// All other state commands from the legacy agent must be ignored.
break ;
2017-11-06 20:54:40 -05:00
}
2017-11-03 20:01:30 -04:00
}
2019-03-06 12:15:32 -05:00
break ;
}
case LegacyMeshProtocol . APPSUBSCRIBERS : {
2019-08-22 18:31:39 -04:00
parent . debug ( 'swarmcmd' , 'APPSUBSCRIBERS' ) ;
2019-03-06 12:15:32 -05:00
break ;
}
default : {
2019-08-22 18:31:39 -04:00
parent . debug ( 'swarmcmd' , 'Unknown command: ' + cmd + ' of len ' + len + '.' ) ;
2017-11-03 20:01:30 -04:00
}
}
2019-03-06 12:15:32 -05:00
return len ;
}
// Called when a legacy agent connects to this server
function onConnection ( socket ) {
// Check for blocked IP address
2019-08-22 18:31:39 -04:00
if ( checkSwarmIpAddress ( socket , obj . args . swarmallowedip ) == false ) { obj . stats . blockedConnect ++ ; parent . debug ( 'swarm' , "New blocked agent connection" ) ; return ; }
2019-03-06 12:15:32 -05:00
obj . stats . connectCount ++ ;
2019-03-09 17:28:08 -05:00
socket . tag = { first : true , clientCert : socket . getPeerCertificate ( true ) , accumulator : "" } ;
2019-08-22 18:31:39 -04:00
parent . debug ( 'swarm' , 'New legacy agent connection' ) ;
2019-03-06 12:15:32 -05:00
if ( ( socket . tag . clientCert == null ) || ( socket . tag . clientCert . subject == null ) ) { obj . stats . noCertConnectCount ++ ; } else { obj . stats . clientCertConnectCount ++ ; }
2018-08-30 15:05:23 -04:00
2019-03-06 12:15:32 -05:00
socket . addListener ( "data" , onData ) ;
2017-11-03 20:01:30 -04:00
socket . addListener ( "close" , function ( ) {
2019-02-27 21:48:50 -05:00
obj . stats . onclose ++ ;
2019-08-22 18:31:39 -04:00
parent . debug ( 'swarm' , 'Connection closed' ) ;
2019-03-09 17:28:08 -05:00
// Perform aggressive cleanup
if ( this . relaySocket ) { try { this . relaySocket . end ( ) ; this . relaySocket . removeAllListeners ( [ "data" , "end" , "error" ] ) ; delete this . relaySocket ; } catch ( ex ) { } }
2019-03-06 12:15:32 -05:00
if ( this . pingTimer != null ) { clearInterval ( this . pingTimer ) ; delete this . pingTimer ; }
if ( this . tag && ( typeof this . tag . taskid == 'number' ) ) {
obj . parent . taskLimiter . completed ( this . tag . taskid ) ; // Indicate this task complete
delete this . tag . taskid ;
2019-01-28 19:53:11 -05:00
}
2019-03-09 17:28:08 -05:00
if ( this . tag ) {
if ( this . tag . accumulator ) { delete this . tag . accumulator ; }
if ( this . tag . clientCert ) { delete this . tag . clientCert ; }
delete this . tag ;
}
this . removeAllListeners ( [ "data" , "close" , "error" ] ) ;
2017-11-03 20:01:30 -04:00
} ) ;
2018-08-30 15:05:23 -04:00
2017-11-03 20:01:30 -04:00
socket . addListener ( "error" , function ( ) {
//console.log("Swarm Error: " + socket.remoteAddress);
} ) ;
}
2017-11-06 20:54:40 -05:00
function getTagClass ( data , tagClass , type ) {
if ( ( data == null ) || ( data . value == null ) ) return ;
for ( var i in data . value ) {
//console.log(JSON.stringify(data.value[i]));
if ( ( data . value [ i ] . tagClass == tagClass ) && ( data . value [ i ] . type == type ) ) {
return data . value [ i ] ;
}
}
}
// Decode a node push block
obj . decodeNodeBlock = function ( data ) {
try {
// Traverse the DER to get the raw data (Not sure if this works all the time)
var info = { } , ptr = 68 , der = forge . asn1 . fromDer ( forge . util . createBuffer ( data , 'binary' ) ) ;
der = getTagClass ( der , 128 , 0 ) ;
der = getTagClass ( der , 0 , 16 ) ;
der = getTagClass ( der , 0 , 16 ) ;
der = getTagClass ( der , 128 , 0 ) ;
der = getTagClass ( der , 0 , 4 ) ;
var binarydata = der . value ;
// Get the basic header values
info . certhashhex = common . rstr2hex ( binarydata . substring ( 0 , 32 ) ) ; // Hash of the complete mesh agent certificate
info . nodeidhex = common . rstr2hex ( binarydata . substring ( 32 , 64 ) ) ; // Old mesh agent nodeid
info . serialNumber = common . ReadIntX ( binarydata , 64 ) ; // Block serial number
// Got thru the sub-blocks
while ( ptr < binarydata . length ) {
var btyp = common . ReadShort ( binarydata , ptr ) , blen = common . ReadShort ( binarydata , ptr + 2 ) , bdata = binarydata . substring ( ptr + 4 , ptr + 4 + blen ) ;
switch ( btyp ) {
case 1 : { // PBST_COMPUTERINFO
info . agenttype = common . ReadShortX ( bdata , 0 ) ;
info . agentbuild = common . ReadShortX ( bdata , 2 ) ;
info . agentversion = common . ReadIntX ( bdata , 4 ) ;
info . agentname = bdata . substring ( 8 , 64 + 8 ) ;
var xx = info . agentname . indexOf ( '\u0000' ) ;
if ( xx >= 0 ) { info . agentname = info . agentname . substring ( 0 , xx ) ; }
info . agentosdesc = bdata . substring ( 64 + 8 , 64 + 64 + 8 ) ;
xx = info . agentosdesc . indexOf ( '\u0000' ) ;
if ( xx >= 0 ) { info . agentosdesc = info . agentosdesc . substring ( 0 , xx ) ; }
return info ;
}
2019-01-04 20:59:13 -05:00
default : {
// All other commands from the legacy agent must be ignored.
break ;
}
2017-11-06 20:54:40 -05:00
}
ptr += blen ;
}
return info ;
2019-03-11 20:33:24 -04:00
} catch ( e ) { }
2017-11-06 20:54:40 -05:00
return null ;
2018-08-30 15:05:23 -04:00
} ;
2017-11-06 20:54:40 -05:00
2017-11-03 20:01:30 -04:00
// Disconnect legacy agent connection
obj . close = function ( socket ) {
2019-02-27 21:48:50 -05:00
obj . stats . close ++ ;
2017-11-03 20:01:30 -04:00
try { socket . close ( ) ; } catch ( e ) { }
2019-02-25 20:30:19 -05:00
socket . xclosed = 1 ;
2018-08-30 15:05:23 -04:00
} ;
2017-11-03 20:01:30 -04:00
2018-08-30 15:05:23 -04:00
obj . SendCommand = function ( socket , cmdid , data ) {
2017-11-06 20:54:40 -05:00
if ( data == null ) { data = '' ; }
Write ( socket , common . ShortToStr ( cmdid ) + common . ShortToStr ( data . length + 4 ) + data ) ;
2018-08-30 15:05:23 -04:00
} ;
2017-11-06 20:54:40 -05:00
2017-11-03 20:01:30 -04:00
function Write ( socket , data ) {
2019-02-27 21:48:50 -05:00
obj . stats . bytesOut += data . length ;
2017-11-03 20:01:30 -04:00
if ( args . swarmdebug ) {
// Print out sent bytes
2019-01-02 21:03:34 -05:00
var buf = Buffer . from ( data , "binary" ) ;
2017-11-06 20:54:40 -05:00
console . log ( 'SWARM --> (' + buf . length + '):' + buf . toString ( 'hex' ) ) ;
2017-11-03 20:01:30 -04:00
socket . write ( buf ) ;
} else {
2019-01-02 21:03:34 -05:00
socket . write ( Buffer . from ( data , "binary" ) ) ;
2017-11-03 20:01:30 -04:00
}
}
2018-08-30 15:05:23 -04:00
2019-01-11 13:02:54 -05:00
// Check if the source IP address is allowed for a given allowed list, return false if not
function checkSwarmIpAddress ( socket , allowedIpList ) {
if ( allowedIpList == null ) { return true ; }
try {
var ip = socket . remoteAddress ;
if ( ip ) { for ( var i = 0 ; i < allowedIpList . length ; i ++ ) { if ( require ( 'ipcheck' ) . match ( ip , allowedIpList [ i ] ) ) { return true ; } } }
} catch ( e ) { console . log ( e ) ; }
return false ;
}
2017-11-03 20:01:30 -04:00
return obj ;
2018-08-30 15:05:23 -04:00
} ;