AMT interceptor performance improvement.
Ylian Saint-Hilaire committed
Oct 14, 2020 at 13:39 UTC
ef49fb575eaa1c5e5b14b5ddf913fb1c5c1ab7d5
2 files changed
+45
-59
interceptor.js
+14
-19
@@ -37,14 +37,11 @@ module.exports.CreateHttpInterceptor = function (args) {
37
38
// Process data coming from Intel AMT
39
obj.processAmtData = function (data) {
40
- obj.amt.acc += data; // Add data to accumulator
40
+ obj.amt.acc += data.toString('binary'); // Add data to accumulator
41
data = '';
42
var datalen = 0;
43
- do {
44
- datalen = data.length;
45
- data += obj.processAmtDataEx();
46
- } while (datalen != data.length); // Process as much data as possible
47
- return data;
43
+ do { datalen = data.length; data += obj.processAmtDataEx(); } while (datalen != data.length); // Process as much data as possible
44
+ return Buffer.from(data, 'binary');
45
};
46
47
// Process data coming from AMT in the accumulator
@@ -122,14 +119,11 @@ module.exports.CreateHttpInterceptor = function (args) {
119
120
// Process data coming from the Browser
121
obj.processBrowserData = function (data) {
125
- obj.ws.acc += data; // Add data to accumulator
122
+ obj.ws.acc += data.toString('binary'); // Add data to accumulator
123
data = '';
124
var datalen = 0;
128
- do {
129
- datalen = data.length;
130
- data += obj.processBrowserDataEx();
131
- } while (datalen != data.length); // Process as much data as possible
132
- return data;
125
+ do { datalen = data.length; data += obj.processBrowserDataEx(); } while (datalen != data.length); // Process as much data as possible
126
+ return Buffer.from(data, 'binary');
127
};
128
129
// Process data coming from the Browser in the accumulator
@@ -279,20 +273,21 @@ module.exports.CreateRedirInterceptor = function (args) {
273
274
// Process data coming from Intel AMT
275
obj.processAmtData = function (data) {
282
- obj.amt.acc += data; // Add data to accumulator
276
+ if ((obj.amt.direct == true) && (obj.amt.acc == '')) { return data; } // Interceptor fast path
277
+ obj.amt.acc += data.toString('binary'); // Add data to accumulator
278
data = '';
279
var datalen = 0;
280
do { datalen = data.length; data += obj.processAmtDataEx(); } while (datalen != data.length); // Process as much data as possible
286
- return data;
281
+ return Buffer.from(data, 'binary');
282
};
283
284
// Process data coming from AMT in the accumulator
285
obj.processAmtDataEx = function () {
286
var r;
292
- if (obj.amt.acc.length == 0) return "";
287
+ if (obj.amt.acc.length == 0) return '';
288
if (obj.amt.direct == true) {
289
var data = obj.amt.acc;
295
- obj.amt.acc = "";
290
+ obj.amt.acc = '';
291
return data;
292
} else {
293
//console.log(obj.amt.acc.charCodeAt(0));
@@ -346,11 +341,12 @@ module.exports.CreateRedirInterceptor = function (args) {
341
342
// Process data coming from the Browser
343
obj.processBrowserData = function (data) {
349
- obj.ws.acc += data; // Add data to accumulator
344
+ if ((obj.ws.direct == true) && (obj.ws.acc == '')) { return data; } // Interceptor fast path
345
+ obj.ws.acc += data.toString('binary'); // Add data to accumulator
346
data = '';
347
var datalen = 0;
348
do { datalen = data.length; data += obj.processBrowserDataEx(); } while (datalen != data.length); // Process as much data as possible
353
- return data;
349
+ return Buffer.from(data, 'binary');
350
};
351
352
// Process data coming from the Browser in the accumulator
@@ -434,7 +430,6 @@ module.exports.CreateRedirInterceptor = function (args) {
430
}
431
default: {
432
obj.ws.error = true;
437
- return '';
433
}
434
}
435
}
webserver.js
+31
-40
@@ -13,17 +13,7 @@
13
/*jshint esversion: 6 */
14
'use strict';
15
16
-/*
17
-class SerialTunnel extends require('stream').Duplex {
18
- constructor(options) { super(options); this.forwardwrite = null; }
19
- updateBuffer(chunk) { this.push(chunk); }
20
- _write(chunk, encoding, callback) { if (this.forwardwrite != null) { this.forwardwrite(chunk); } else { console.err("Failed to fwd _write."); } if (callback) callback(); } // Pass data written to forward
21
- _read(size) { } // Push nothing, anything to read should be pushed from updateBuffer()
22
-}
23
-*/
24
-
25
-// Older NodeJS does not support the keyword "class", so we do without using this syntax
26
-// TODO: Validate that it's the same as above and that it works.
16
+// SerialTunnel object is used to embed TLS within another connection.
17
function SerialTunnel(options) {
18
var obj = new require('stream').Duplex(options);
19
obj.forwardwrite = null;
@@ -3388,7 +3378,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3378
3379
// Setup a new CIRA channel
3380
if ((port == 16993) || (port == 16995)) {
3391
- // Perform TLS - ( TODO: THIS IS BROKEN on Intel AMT v7 but works on v10, Not sure why. Well, could be broken TLS 1.0 in firmware )
3381
+ // Perform TLS
3382
var ser = new SerialTunnel();
3383
var chnl = parent.mpsserver.SetupChannel(ciraconn, port);
3384
@@ -3415,7 +3405,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3405
// Decrypted tunnel from TLS communcation to be forwarded to websocket
3406
tlsock.on('data', function (data) {
3407
// AMT/TLS ---> WS
3418
- if (ws.interceptor) { data = Buffer.from(ws.interceptor.processAmtData(data.toString('binary')), 'binary'); } // Run data thru interceptor
3408
+ if (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor
3409
try { ws.send(data); } catch (ex) { }
3410
});
3411
@@ -3430,11 +3420,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3420
3421
ws.forwardclient.onData = function (ciraconn, data) {
3422
// Run data thru interceptor
3433
- if (ws.interceptor) { data = Buffer.from(ws.interceptor.processAmtData(data.toString('binary')), 'binary'); }
3423
+ if (ws.interceptor) { data = ws.interceptor.processAmtData(data); }
3424
3425
if (data.length > 0) {
3426
if (ws.logfile == null) {
3437
- try { ws.send(data); } catch (e) { } // TODO: Add TLS support
3427
+ try { ws.send(data); } catch (e) { }
3428
} else {
3429
// Log to recording file
3430
recordingEntry(ws.logfile.fd, 2, 0, data, function () { try { ws.send(data); } catch (ex) { console.log(ex); } }); // TODO: Add TLS support
@@ -3442,10 +3432,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3432
}
3433
};
3434
3445
- ws.forwardclient.onSendOk = function (ciraconn) {
3446
- // TODO: Flow control? (Dont' really need it with AMT, but would be nice)
3447
- //console.log('onSendOk');
3448
- };
3435
+ // TODO: Flow control? (Dont' really need it with AMT, but would be nice)
3436
+ ws.forwardclient.onSendOk = function (ciraconn) { };
3437
}
3438
};
3439
} else {
@@ -3462,24 +3450,22 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3450
ws.forwardclient.onData = function (ciraconn, data) {
3451
//parent.debug('webrelaydata', 'Relay CIRA data to WS', data.length);
3452
3465
- // Run data thru interceptor
3466
- if (ws.interceptor) { data = Buffer.from(ws.interceptor.processAmtData(data.toString('binary')), 'binary'); }
3453
+ // Run data thru interceptorp
3454
+ if (ws.interceptor) { data = ws.interceptor.processAmtData(data); }
3455
3456
//console.log('AMT --> WS', Buffer.from(data, 'binary').toString('hex'));
3457
if (data.length > 0) {
3458
if (ws.logfile == null) {
3471
- try { ws.send(data); } catch (e) { } // TODO: Add TLS support
3459
+ try { ws.send(data); } catch (e) { }
3460
} else {
3461
// Log to recording file
3474
- recordingEntry(ws.logfile.fd, 2, 0, data, function () { try { ws.send(data); } catch (ex) { console.log(ex); } }); // TODO: Add TLS support
3462
+ recordingEntry(ws.logfile.fd, 2, 0, data, function () { try { ws.send(data); } catch (ex) { console.log(ex); } });
3463
}
3464
}
3465
};
3466
3479
- ws.forwardclient.onSendOk = function (ciraconn) {
3480
- // TODO: Flow control? (Dont' really need it with AMT, but would be nice)
3481
- //console.log('onSendOk');
3482
- };
3467
+ // TODO: Flow control? (Dont' really need it with AMT, but would be nice)
3468
+ ws.forwardclient.onSendOk = function (ciraconn) { };
3469
}
3470
3471
// When data is received from the web socket, forward the data into the associated CIRA cahnnel.
@@ -3489,7 +3475,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3475
if (typeof data == 'string') { data = Buffer.from(data, 'binary'); }
3476
3477
// WS ---> AMT/TLS
3492
- if (ws.interceptor) { data = Buffer.from(ws.interceptor.processBrowserData(data.toString('binary')), 'binary'); } // Run data thru interceptor
3478
+ if (ws.interceptor) { data = ws.interceptor.processBrowserData(data); } // Run data thru interceptor
3479
3480
// Log to recording file
3481
if (ws.logfile == null) {
@@ -3505,10 +3491,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3491
ws.on('error', function (err) {
3492
console.log('CIRA server websocket error from ' + req.clientIp + ', ' + err.toString().split('\r')[0] + '.');
3493
parent.debug('webrelay', 'Websocket relay closed on error.');
3508
- if (ws.forwardclient && ws.forwardclient.close) { ws.forwardclient.close(); } // TODO: If TLS is used, we need to close the socket that is wrapped by TLS
3494
+
3495
+ // Websocket closed, close the CIRA channel and TLS session.
3496
+ if (ws.forwardclient) {
3497
+ if (ws.forwardclient.close) { ws.forwardclient.close(); } // NonTLS, close the CIRA channel
3498
+ if (ws.forwardclient.end) { ws.forwardclient.end(); } // TLS, close the TLS session
3499
+ if (ws.forwardclient.chnl) { ws.forwardclient.chnl.close(); } // TLS, close the CIRA channel
3500
+ delete ws.forwardclient;
3501
+ }
3502
3503
// Close the recording file
3511
- if (ws.logfile != null) { recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd, ws) { obj.fs.close(fd); ws.logfile = null; }, ws); }
3504
+ if (ws.logfile != null) { recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd, ws) { obj.fs.close(fd); delete ws.logfile; }, ws); }
3505
});
3506
3507
// If the web socket is closed, close the associated TCP connection.
@@ -3520,10 +3513,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3513
if (ws.forwardclient.close) { ws.forwardclient.close(); } // NonTLS, close the CIRA channel
3514
if (ws.forwardclient.end) { ws.forwardclient.end(); } // TLS, close the TLS session
3515
if (ws.forwardclient.chnl) { ws.forwardclient.chnl.close(); } // TLS, close the CIRA channel
3516
+ delete ws.forwardclient;
3517
}
3518
3519
// Close the recording file
3526
- if (ws.logfile != null) { recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd, ws) { obj.fs.close(fd); ws.logfile = null; }, ws); }
3520
+ if (ws.logfile != null) { recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd, ws) { obj.fs.close(fd); delete ws.logfile; }, ws); }
3521
});
3522
3523
// Fetch Intel AMT credentials & Setup interceptor
@@ -3546,20 +3540,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3540
3541
// When data is received from the web socket, forward the data into the associated TCP connection.
3542
ws.on('message', function (msg) {
3549
- if (obj.parent.debugLevel >= 1) { // DEBUG
3550
- parent.debug('webrelaydata', 'TCP relay data to ' + node.host + ', ' + msg.length + ' bytes');
3551
- //if (obj.parent.debugLevel >= 4) { parent.debug('webrelaydatahex', ' ' + msg.toString('hex')); }
3552
- }
3553
- msg = msg.toString('binary');
3543
+ //parent.debug('webrelaydata', 'TCP relay data to ' + node.host + ', ' + msg.length + ' bytes');
3544
+
3545
+ if (typeof msg == 'string') { msg = Buffer.from(msg, 'binary'); }
3546
if (ws.interceptor) { msg = ws.interceptor.processBrowserData(msg); } // Run data thru interceptor
3547
3548
// Log to recording file
3549
if (ws.logfile == null) {
3550
// Forward data to the associated TCP connection.
3559
- try { ws.forwardclient.write(Buffer.from(msg, 'binary')); } catch (ex) { }
3551
+ try { ws.forwardclient.write(msg); } catch (ex) { }
3552
} else {
3553
// Log to recording file
3562
- msg = Buffer.from(msg, 'binary');
3554
recordingEntry(ws.logfile.fd, 2, 2, msg, function () { try { ws.forwardclient.write(msg); } catch (ex) { } });
3555
}
3556
});
@@ -3622,6 +3613,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3613
3614
// When we receive data on the TCP connection, forward it back into the web socket connection.
3615
ws.forwardclient.on('data', function (data) {
3616
+ if (typeof data == 'string') { data = Buffer.from(data, 'binary'); }
3617
if (obj.parent.debugLevel >= 1) { // DEBUG
3618
parent.debug('webrelaydata', 'TCP relay data from ' + node.host + ', ' + data.length + ' bytes.');
3619
//if (obj.parent.debugLevel >= 4) { Debug(4, ' ' + Buffer.from(data, 'binary').toString('hex')); }
@@ -3629,10 +3621,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3621
if (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor
3622
if (ws.logfile == null) {
3623
// No logging
3632
- try { ws.send(Buffer.from(data, 'binary')); } catch (e) { }
3624
+ try { ws.send(data); } catch (e) { }
3625
} else {
3626
// Log to recording file
3635
- data = Buffer.from(data, 'binary');
3627
recordingEntry(ws.logfile.fd, 2, 0, data, function () { try { ws.send(data); } catch (e) { } });
3628
}
3629
});