Added tasklimiter and improvements to agent meshcore update system.
Ylian Saint-Hilaire committed
Jan 16, 2021 at 23:35 UTC
cd84af5cb9acb1dea8f8e1590acf4a0a6cae51b7
3 files changed
+81
-40
agents/meshcore.js
+12
-9
@@ -905,7 +905,7 @@ function createMeshCore(agent)
905
switch (data.action)
906
{
907
case 'agentupdate':
908
- agentUpdate_Start(data.url, { hash: data.hash, tlshash: data.servertlshash });
908
+ agentUpdate_Start(data.url, { hash: data.hash, tlshash: data.servertlshash, sessionid: data.sessionid });
909
break;
910
case 'msg': {
911
switch (data.type)
@@ -3053,11 +3053,11 @@ function createMeshCore(agent)
3053
break;
3054
}
3055
case 'agentupdate':
3056
- require('MeshAgent').SendCommand({ action: 'agentupdate' });
3056
+ require('MeshAgent').SendCommand({ action: 'agentupdate', sessionid: sessionid });
3057
break;
3058
case 'agentupdateex':
3059
// Perform an direct agent update without requesting any information from the server, this should not typically be used.
3060
- agentUpdate_Start(null, { session: sessionid });
3060
+ agentUpdate_Start(null, { sessionid: sessionid });
3061
break;
3062
case 'msh':
3063
response = JSON.stringify(_MSH(), null, 2);
@@ -4343,7 +4343,7 @@ function createMeshCore(agent)
4343
function agentUpdate_Start(updateurl, updateoptions)
4344
{
4345
// If this value is null
4346
- var sessionid = updateoptions != null ? updateoptions.session : null; // If this is null, messages will be broadcast. Otherwise they will be unicasted
4346
+ var sessionid = (updateoptions != null) ? updateoptions.sessionid : null; // If this is null, messages will be broadcast. Otherwise they will be unicasted
4347
4348
if (this._selfupdate != null)
4349
{
@@ -4380,7 +4380,7 @@ function createMeshCore(agent)
4380
return;
4381
}
4382
4383
- sendConsoleText('Downloading update...', sessionid);
4383
+ if (sessionid != null) { sendConsoleText('Downloading update...', sessionid); }
4384
var options = require('http').parseUri(updateurl != null ? updateurl : require('MeshAgent').ServerUrl);
4385
options.protocol = 'https:';
4386
if (updateurl == null) { options.path = ('/meshagents?id=' + require('MeshAgent').ARCHID); }
@@ -4422,7 +4422,7 @@ function createMeshCore(agent)
4422
{
4423
if (updateoptions.hash.toLowerCase() == h.toString('hex').toLowerCase())
4424
{
4425
- sendConsoleText('Download complete. HASH verified.', sessionid);
4425
+ if (sessionid != null) { sendConsoleText('Download complete. HASH verified.', sessionid); }
4426
}
4427
else
4428
{
@@ -4433,10 +4433,13 @@ function createMeshCore(agent)
4433
}
4434
else
4435
{
4436
- sendConsoleText('Download complete. HASH=' + h.toString('hex'), sessionid);
4436
+ if (sessionid != null) { sendConsoleText('Download complete. HASH=' + h.toString('hex'), sessionid); }
4437
}
4438
4439
- sendConsoleText('Updating and restarting agent...', sessionid);
4439
+ // Send an indication to the server that we got the update download correctly.
4440
+ try { mesh.SendCommand({ action: 'agentupdatedownloaded' }); } catch (e) { }
4441
+
4442
+ if (sessionid != null) { sendConsoleText('Updating and restarting agent...', sessionid); }
4443
if (process.platform == 'win32')
4444
{
4445
// Use _wexecve() equivalent to perform the update
@@ -4458,7 +4461,7 @@ function createMeshCore(agent)
4461
m |= (require('fs').CHMOD_MODES.S_IXUSR | require('fs').CHMOD_MODES.S_IXGRP | require('fs').CHMOD_MODES.S_IXOTH);
4462
require('fs').chmodSync(process.execPath, m);
4463
4461
- sendConsoleText('Restarting service...', sessionid);
4464
+ if (sessionid != null) { sendConsoleText('Restarting service...', sessionid); }
4465
try
4466
{
4467
// restart service
agents/recoverycore.js
+11
-8
@@ -86,7 +86,7 @@ function windows_execve(name, agentfilename, sessionid)
86
function agentUpdate_Start(updateurl, updateoptions)
87
{
88
// If this value is null
89
- var sessionid = updateoptions != null ? updateoptions.session : null; // If this is null, messages will be broadcast. Otherwise they will be unicasted
89
+ var sessionid = (updateoptions != null) ? updateoptions.sessionid : null; // If this is null, messages will be broadcast. Otherwise they will be unicasted
90
91
if (this._selfupdate != null)
92
{
@@ -123,7 +123,7 @@ function agentUpdate_Start(updateurl, updateoptions)
123
return;
124
}
125
126
- sendConsoleText('Downloading update...', sessionid);
126
+ if (sessionid != null) { sendConsoleText('Downloading update...', sessionid); }
127
var options = require('http').parseUri(updateurl != null ? updateurl : require('MeshAgent').ServerUrl);
128
options.protocol = 'https:';
129
if (updateurl == null) { options.path = ('/meshagents?id=' + require('MeshAgent').ARCHID); }
@@ -165,7 +165,7 @@ function agentUpdate_Start(updateurl, updateoptions)
165
{
166
if (updateoptions.hash.toLowerCase() == h.toString('hex').toLowerCase())
167
{
168
- sendConsoleText('Download complete. HASH verified.', sessionid);
168
+ if (sessionid != null) { sendConsoleText('Download complete. HASH verified.', sessionid); }
169
}
170
else
171
{
@@ -179,7 +179,10 @@ function agentUpdate_Start(updateurl, updateoptions)
179
sendConsoleText('Download complete. HASH=' + h.toString('hex'), sessionid);
180
}
181
182
- sendConsoleText('Updating and restarting agent...', sessionid);
182
+ // Send an indication to the server that we got the update download correctly.
183
+ try { mesh.SendCommand({ action: 'agentupdatedownloaded' }); } catch (e) { }
184
+
185
+ if (sessionid != null) { sendConsoleText('Updating and restarting agent...', sessionid); }
186
if (process.platform == 'win32')
187
{
188
// Use _wexecve() equivalent to perform the update
@@ -201,7 +204,7 @@ function agentUpdate_Start(updateurl, updateoptions)
204
m |= (require('fs').CHMOD_MODES.S_IXUSR | require('fs').CHMOD_MODES.S_IXGRP | require('fs').CHMOD_MODES.S_IXOTH);
205
require('fs').chmodSync(process.execPath, m);
206
204
- sendConsoleText('Restarting service...', sessionid);
207
+ if (sessionid != null) { sendConsoleText('Restarting service...', sessionid); }
208
try
209
{
210
// restart service
@@ -406,7 +409,7 @@ require('MeshAgent').AddCommandHandler(function (data)
409
switch (data.action)
410
{
411
case 'agentupdate':
409
- agentUpdate_Start(data.url, { hash: data.hash, tlshash: data.servertlshash });
412
+ agentUpdate_Start(data.url, { hash: data.hash, tlshash: data.servertlshash, sessionid: data.sessionid });
413
break;
414
case 'msg':
415
{
@@ -662,11 +665,11 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
665
break;
666
case 'agentupdate':
667
// Request that the server send a agent update command
665
- require('MeshAgent').SendCommand({ action: 'agentupdate' });
668
+ require('MeshAgent').SendCommand({ action: 'agentupdate', sessionid: sessionid });
669
break;
670
case 'agentupdateex':
671
// Perform an direct agent update without requesting any information from the server, this should not typically be used.
669
- agentUpdate_Start(null, { session: sessionid });
672
+ agentUpdate_Start(null, { sessionid: sessionid });
673
break;
674
case 'osinfo': { // Return the operating system information
675
var i = 1;
meshagent.js
+58
-23
@@ -89,7 +89,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
89
// Set this agent as no longer authenticated
90
obj.authenticated = -1;
91
92
- // If we where updating the agent, clean that up.
92
+ // If we where updating the agent using native method, clean that up.
93
if (obj.agentUpdate != null) {
94
if (obj.agentUpdate.fd) { try { parent.fs.close(obj.agentUpdate.fd); } catch (ex) { } }
95
parent.parent.taskLimiter.completed(obj.agentUpdate.taskid); // Indicate this task complete
@@ -97,6 +97,12 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
97
delete obj.agentUpdate;
98
}
99
100
+ // If we where updating the agent meshcore method, clean that up.
101
+ if (obj.agentCoreUpdateTaskId != null) {
102
+ parent.parent.taskLimiter.completed(obj.agentCoreUpdateTaskId);
103
+ delete obj.agentCoreUpdateTaskId;
104
+ }
105
+
106
// Perform timer cleanup
107
if (obj.pingtimer) { clearInterval(obj.pingtimer); delete obj.pingtimer; }
108
if (obj.pongtimer) { clearInterval(obj.pongtimer); delete obj.pongtimer; }
@@ -238,7 +244,6 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
244
if (agentUpdateMethod === 2) { // Use meshcore agent update system
245
// Send the recovery core to the agent, if the agent is capable of running one
246
if (((obj.agentInfo.capabilities & 16) != 0) && (parent.parent.meshAgentsArchitectureNumbers[obj.agentInfo.agentId].core != null)) {
241
- //obj.agentCoreCheck = 1001;
247
obj.agentCoreUpdate = true;
248
obj.sendBinary(common.ShortToStr(11) + common.ShortToStr(0));
249
}
@@ -1152,17 +1157,26 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1157
{
1158
if ((obj.agentCoreUpdate === true) && (obj.agentExeInfo != null)) {
1159
// Agent update. The recovery core was loaded in the agent, send a command to update the agent
1155
- var cmd = { action: 'agentupdate', url: obj.agentExeInfo.url, hash: obj.agentExeInfo.hashhex };
1156
- // Add the hash
1157
- if (obj.agentExeInfo.fileHash != null) { cmd.hash = obj.agentExeInfo.fileHashHex; } else { cmd.hash = obj.agentExeInfo.hashhex; }
1158
- // Add server TLS cert hash
1159
- if (parent.parent.args.ignoreagenthashcheck !== true) {
1160
- const tlsCertHash = parent.webCertificateFullHashs[domain.id];
1161
- if (tlsCertHash != null) { cmd.servertlshash = Buffer.from(tlsCertHash, 'binary').toString('hex'); }
1162
- }
1163
- // Send the agent update command
1164
- obj.send(JSON.stringify(cmd));
1165
- //delete obj.agentCoreUpdate;
1160
+ parent.parent.taskLimiter.launch(function (argument, taskid, taskLimiterQueue) { // Medium priority task
1161
+ // If agent disconnection, complete and exit now.
1162
+ if (obj.authenticated != 2) { parent.parent.taskLimiter.completed(taskid); return; }
1163
+
1164
+ // Agent update. The recovery core was loaded in the agent, send a command to update the agent
1165
+ obj.agentCoreUpdateTaskId = taskid;
1166
+ var cmd = { action: 'agentupdate', url: obj.agentExeInfo.url, hash: obj.agentExeInfo.hashhex };
1167
+
1168
+ // Add the hash
1169
+ if (obj.agentExeInfo.fileHash != null) { cmd.hash = obj.agentExeInfo.fileHashHex; } else { cmd.hash = obj.agentExeInfo.hashhex; }
1170
+
1171
+ // Add server TLS cert hash
1172
+ if (parent.parent.args.ignoreagenthashcheck !== true) {
1173
+ const tlsCertHash = parent.webCertificateFullHashs[domain.id];
1174
+ if (tlsCertHash != null) { cmd.servertlshash = Buffer.from(tlsCertHash, 'binary').toString('hex'); }
1175
+ }
1176
+
1177
+ // Send the agent update command
1178
+ obj.send(JSON.stringify(cmd));
1179
+ }, null, 1);
1180
} else {
1181
// Sent by the agent to update agent information
1182
ChangeAgentCoreInfo(command);
@@ -1456,17 +1470,38 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1470
break;
1471
}
1472
case 'agentupdate': {
1459
- // Agent is requesting an agent update
1460
- var cmd = { action: 'agentupdate', url: obj.agentExeInfo.url, hash: obj.agentExeInfo.hashhex };
1461
- // Add the hash
1462
- if (obj.agentExeInfo.fileHash != null) { cmd.hash = obj.agentExeInfo.fileHashHex; } else { cmd.hash = obj.agentExeInfo.hashhex; }
1463
- // Add server TLS cert hash
1464
- if (parent.parent.args.ignoreagenthashcheck !== true) {
1465
- const tlsCertHash = parent.webCertificateFullHashs[domain.id];
1466
- if (tlsCertHash != null) { cmd.servertlshash = Buffer.from(tlsCertHash, 'binary').toString('hex'); }
1473
+ var func = function agentUpdateFunc(argument, taskid, taskLimiterQueue) { // Medium priority task
1474
+ // If agent disconnection, complete and exit now.
1475
+ if (obj.authenticated != 2) { parent.parent.taskLimiter.completed(taskid); return; }
1476
+
1477
+ // Agent is requesting an agent update
1478
+ obj.agentCoreUpdateTaskId = taskid;
1479
+ var cmd = { action: 'agentupdate', url: obj.agentExeInfo.url, hash: obj.agentExeInfo.hashhex, sessionid: agentUpdateFunc.sessionid };
1480
+
1481
+ // Add the hash
1482
+ if (obj.agentExeInfo.fileHash != null) { cmd.hash = obj.agentExeInfo.fileHashHex; } else { cmd.hash = obj.agentExeInfo.hashhex; }
1483
+
1484
+ // Add server TLS cert hash
1485
+ if (parent.parent.args.ignoreagenthashcheck !== true) {
1486
+ const tlsCertHash = parent.webCertificateFullHashs[domain.id];
1487
+ if (tlsCertHash != null) { cmd.servertlshash = Buffer.from(tlsCertHash, 'binary').toString('hex'); }
1488
+ }
1489
+
1490
+ // Send the agent update command
1491
+ obj.send(JSON.stringify(cmd));
1492
+ }
1493
+ func.sessionid = command.sessionid;
1494
+
1495
+ // Agent update. The recovery core was loaded in the agent, send a command to update the agent
1496
+ parent.parent.taskLimiter.launch(func, null, 1);
1497
+ break;
1498
+ }
1499
+ case 'agentupdatedownloaded': {
1500
+ if (obj.agentCoreUpdateTaskId != null) {
1501
+ // Indicate this udpate task is complete
1502
+ parent.parent.taskLimiter.completed(obj.agentCoreUpdateTaskId);
1503
+ delete obj.agentCoreUpdateTaskId;
1504
}
1468
- // Send the agent update command
1469
- obj.send(JSON.stringify(cmd));
1505
break;
1506
}
1507
default: {