Merged APF and MPS servers, improved APF client.

Ylian Saint-Hilaire committed Oct 8, 2020 at 19:47 UTC bc4e07b5fe84c4480b7c809a82815cd37595dbeb
8 files changed +499 -1246
agents/modules_meshcore/apfclient.js
+71 -117
@@ -6,60 +6,30 @@
6 * @version v0.0.1
7 */
8
9 -function CreateAPFClient(parent, args) {
9 +function CreateAPFClient(parent, args) {
10 var obj = {};
11 obj.parent = parent;
12 obj.args = args;
13 obj.http = require('http');
14 - //obj.common = require('common');
15 - obj.net = require('net');
14 + obj.net = require('net');
15 obj.forwardClient = null;
16 obj.downlinks = {};
17 obj.pfwd_idx = 0;
19 - // keep alive timer
20 - obj.timer = null;
21 -
22 - // some function copied from common.js
23 - function ReadInt(v, p) {
24 - return (v.charCodeAt(p) * 0x1000000) + (v.charCodeAt(p + 1) << 16) + (v.charCodeAt(p + 2) << 8) + v.charCodeAt(p + 3);
25 - }; // We use "*0x1000000" instead of "<<24" because the shift converts the number to signed int32.
26 -
27 - function IntToStr(v) {
28 - return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF);
29 - };
30 -
31 - function hex2rstr(d) {
32 - var r = '', m = ('' + d).match(/../g), t;
33 - while (t = m.shift()) { r += String.fromCharCode('0x' + t); }
34 - return r;
35 - };
36 -
37 - // Convert decimal to hex
38 - function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); };
39 -
40 - // Convert a raw string to a hex string
41 - function rstr2hex(input) {
42 - var r = '', i;
43 - for (i = 0; i < input.length; i++) { r += char2hex(input.charCodeAt(i)); }
44 - return r;
45 - };
46 -
47 - function d2h(d) {
48 - return (d / 256 + 1 / 512).toString(16).substring(2, 4);
49 - }
50 -
51 - function buf2hex(input) {
52 - var r = '', i;
53 - for (i = 0; i < input.length; i++) { r += d2h(input[i]); }
54 - return r;
55 - };
18 + obj.timer = null; // Keep alive timer
19 +
20 + // Function copied from common.js
21 + function ReadInt(v, p) { return (v.charCodeAt(p) * 0x1000000) + (v.charCodeAt(p + 1) << 16) + (v.charCodeAt(p + 2) << 8) + v.charCodeAt(p + 3); }; // We use "*0x1000000" instead of "<<24" because the shift converts the number to signed int32.
22 + function IntToStr(v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); };
23 + function hex2rstr(d) { var r = '', m = ('' + d).match(/../g), t; while (t = m.shift()) { r += String.fromCharCode('0x' + t); } return r; };
24 + function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); }; // Convert decimal to hex
25 + function rstr2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += char2hex(input.charCodeAt(i)); } return r; }; // Convert a raw string to a hex string
26 + function d2h(d) { return (d / 256 + 1 / 512).toString(16).substring(2, 4); }
27 + function buf2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += d2h(input[i]); } return r; };
28 + function Debug(str) { if (obj.parent.debug) { console.log(str); } }
29 + function guidToStr(g) { return g.substring(6, 8) + g.substring(4, 6) + g.substring(2, 4) + g.substring(0, 2) + "-" + g.substring(10, 12) + g.substring(8, 10) + "-" + g.substring(14, 16) + g.substring(12, 14) + "-" + g.substring(16, 20) + "-" + g.substring(20); }
30 + function strToGuid(s) { s = s.replace(/-/g, ''); var ret = s.substring(6, 8) + s.substring(4, 6) + s.substring(2, 4) + s.substring(0, 2) + s.substring(10, 12) + s.substring(8, 10) + s.substring(14, 16) + s.substring(12, 14) + s.substring(16, 20) + s.substring(20); return ret; }
31 + function binzerostring(len) { var res = ''; for (var l = 0; l < len; l++) { res += String.fromCharCode(0 & 0xFF); } return res; }
32
57 -
58 - function Debug(str) {
59 - if (obj.parent.debug) {
60 - console.log(str);
61 - }
62 - }
33 // CIRA state
34 var CIRASTATE = {
35 INITIAL: 0,
@@ -85,9 +55,10 @@ function CreateAPFClient(parent, args) {
55 obj.RedirectStartKvm = String.fromCharCode(0x10, 0x01, 0x00, 0x00, 0x4b, 0x56, 0x4d, 0x52);
56 obj.RedirectStartIder = String.fromCharCode(0x10, 0x00, 0x00, 0x00, 0x49, 0x44, 0x45, 0x52);
57
58 + // Intel AMT forwarded port list for non-TLS mode
59 + //var pfwd_ports = [16992, 623, 16994, 5900];
60 + var pfwd_ports = [ 16992 ];
61
89 - // AMT forwarded port list for non-TLS mode
90 - var pfwd_ports = [16992, 623, 16994, 5900];
62 // protocol definitions
63 var APFProtocol = {
64 UNKNOWN: 0,
@@ -152,7 +123,7 @@ function CreateAPFClient(parent, args) {
123 Debug("APF Secure WebSocket connected.");
124 //console.log(JSON.stringify(resp));
125 obj.forwardClient.tag = { accumulator: [] };
155 - obj.forwardClient.ws = ws;
126 + obj.forwardClient.ws = ws;
127 obj.forwardClient.ws.on('end', function () {
128 Debug("APF: Connection is closing.");
129 if (obj.timer != null) {
@@ -162,12 +133,12 @@ function CreateAPFClient(parent, args) {
133 });
134
135 obj.forwardClient.ws.on('data', function (data) {
165 - obj.forwardClient.tag.accumulator += hex2rstr(buf2hex(data));
136 + obj.forwardClient.tag.accumulator += hex2rstr(buf2hex(data));
137 try {
138 var len = 0;
139 do {
140 len = ProcessData(obj.forwardClient);
170 - if (len > 0) {
141 + if (len > 0) {
142 obj.forwardClient.tag.accumulator = obj.forwardClient.tag.accumulator.slice(len);
143 }
144 if (obj.cirastate == CIRASTATE.FAILED) {
@@ -178,44 +149,26 @@ function CreateAPFClient(parent, args) {
149 } catch (e) {
150 Debug(e);
151 }
181 - });
182 -
152 + });
153 +
154 obj.forwardClient.ws.on('error', function (e) {
155 Debug("APF: Connection error, ending connecting.");
156 if (obj.timer != null) {
157 clearInterval(obj.timer);
158 obj.timer = null;
159 }
189 - });
160 + });
161
162 obj.state = CIRASTATE.INITIAL;
163 SendProtocolVersion(obj.forwardClient.ws, obj.args.clientuuid);
164 SendServiceRequest(obj.forwardClient.ws, 'auth@amt.intel.com');
165 }
166
196 - function guidToStr(g) { return g.substring(6, 8) + g.substring(4, 6) + g.substring(2, 4) + g.substring(0, 2) + "-" + g.substring(10, 12) + g.substring(8, 10) + "-" + g.substring(14, 16) + g.substring(12, 14) + "-" + g.substring(16, 20) + "-" + g.substring(20); }
197 - function strToGuid(s) {
198 - s = s.replace(/-/g, '');
199 - var ret = s.substring(6, 8) + s.substring(4, 6) + s.substring(2, 4) + s.substring(0, 2);
200 - ret += s.substring(10, 12) + s.substring(8, 10) + s.substring(14, 16) + s.substring(12, 14) + s.substring(16, 20) + s.substring(20);
201 - return ret;
202 - }
203 -
204 - function binzerostring(len) {
205 - var res='';
206 - for (var l=0; l< len ; l++) {
207 - res+=String.fromCharCode(0 & 0xFF);
208 - }
209 - return res;
210 - }
211 -
212 -
213 -
214 - function SendProtocolVersion(socket, uuid) {
167 + function SendProtocolVersion(socket, uuid) {
168 var buuid = strToGuid(uuid);
169 var data = String.fromCharCode(APFProtocol.PROTOCOLVERSION) + '' + IntToStr(1) + IntToStr(0) + IntToStr(0) + hex2rstr(buuid) + binzerostring(64);
217 - socket.write(data);
218 - Debug("APF: Send protocol version 1 0 " + uuid);
170 + socket.write(data);
171 + Debug("APF: Send protocol version 1 0 " + uuid);
172 obj.cirastate = CIRASTATE.PROTOCOL_VERSION_SENT;
173 }
174
@@ -267,7 +220,8 @@ function CreateAPFClient(parent, args) {
220 var len = socket.tag.accumulator.length;
221 var data = socket.tag.accumulator;
222 if (len == 0) { return 0; }
270 - // respond to MPS according to obj.cirastate
223 +
224 + // Respond to MPS according to obj.cirastate
225 switch (cmd) {
226 case APFProtocol.SERVICE_ACCEPT: {
227 var slen = ReadInt(data, 1);
@@ -325,39 +279,50 @@ function CreateAPFClient(parent, args) {
279 }
280 // Channel management
281 case APFProtocol.CHANNEL_OPEN: {
328 - //parse CHANNEL OPEN request
282 + // Parse CHANNEL OPEN request
283 var p_res = parseChannelOpen(data);
284 Debug("APF: CHANNEL_OPEN request: " + JSON.stringify(p_res));
285 // Check if target port is in pfwd_ports
286 if (pfwd_ports.indexOf(p_res.target_port) >= 0) {
333 - // connect socket to that port
334 - obj.downlinks[p_res.sender_chan] = obj.net.createConnection({ host: obj.args.clientaddress, port: p_res.target_port }, function () {
335 - //obj.downlinks[p_res.sender_chan].setEncoding('binary');//assume everything is binary, not interpreting
287 + // Connect socket to that port
288 + var chan = obj.net.createConnection({ host: obj.args.clientaddress, port: p_res.target_port }, function () {
289 + //require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: "CHANNEL_OPEN-open" });
290 + // obj.downlinks[p_res.sender_chan].setEncoding('binary');//assume everything is binary, not interpreting
291 SendChannelOpenConfirm(socket.ws, p_res);
292 });
293
339 - obj.downlinks[p_res.sender_chan].on('data', function (ddata) {
340 - //Relay data to fordwardclient
294 + // Setup flow control
295 + chan.maxInWindow = p_res.window_size; // Oddly, we are using the same window size as the other side.
296 + chan.curInWindow = 0;
297 +
298 + chan.on('data', function (ddata) {
299 + // Relay data to fordwardclient
300 + // TODO: Implement flow control
301 SendChannelData(socket.ws, p_res.sender_chan, ddata.length, ddata);
302 });
303
344 - obj.downlinks[p_res.sender_chan].on('error', function (e) {
304 + chan.on('error', function (e) {
305 Debug("Downlink connection error: " + e);
306 });
307
348 - obj.downlinks[p_res.sender_chan].on('end', function () {
349 - if (obj.downlinks[p_res.sender_chan]) {
308 + chan.on('end', function () {
309 + var chan = obj.downlinks[p_res.sender_chan];
310 + if (chan != null) {
311 try {
312 Debug("Socket ends.");
313 SendChannelClose(socket.ws, p_res.sender_chan);
353 - // add some delay before removing... otherwise race condition
354 - setTimeout(function () { delete obj.downlinks[p_res.sender_chan];},100);
314 + chan.xclosed = 1;
315 + // Add some delay before removing... otherwise race condition
316 + setTimeout(function () { delete obj.downlinks[p_res.sender_chan]; }, 100);
317 } catch (e) {
318 Debug("Downlink connection exception: " + e);
319 }
320 }
321 });
322 +
323 + obj.downlinks[p_res.sender_chan] = chan;
324 } else {
325 + // Not a supported port, fail the connection
326 SendChannelOpenFailure(socket.ws, p_res);
327 }
328 return p_res.len;
@@ -369,11 +334,12 @@ function CreateAPFClient(parent, args) {
334 case APFProtocol.CHANNEL_CLOSE: {
335 var rcpt_chan = ReadInt(data, 1);
336 Debug("APF: CHANNEL_CLOSE: " + rcpt_chan);
372 - SendChannelClose(socket.ws, rcpt_chan);
373 - try {
374 - obj.downlinks[rcpt_chan].end();
337 + var chan = obj.downlinks[rcpt_chan];
338 + if ((chan != null) && (chan.xclosed !== 1)) {
339 + SendChannelClose(socket.ws, rcpt_chan);
340 + try { obj.downlinks[rcpt_chan].end(); } catch (e) { }
341 delete obj.downlinks[rcpt_chan];
376 - } catch (e) { }
342 + }
343 return 5;
344 }
345 case APFProtocol.CHANNEL_DATA: {
@@ -381,11 +347,14 @@ function CreateAPFClient(parent, args) {
347 var rcpt_chan = ReadInt(data, 1);
348 var chan_data_len = ReadInt(data, 5);
349 var chan_data = data.substring(9, 9 + chan_data_len);
384 - if (obj.downlinks[rcpt_chan]) {
350 + var chan = obj.downlinks[rcpt_chan];
351 + if (chan != null) {
352 + chan.curInWindow += chan_data_len;
353 try {
386 - obj.downlinks[rcpt_chan].write(chan_data, 'binary', function () {
354 + chan.write(chan_data, 'binary', function () {
355 Debug("Write completed.");
388 - SendChannelWindowAdjust(socket.ws, rcpt_chan, chan_data_len);//I have full window capacity now
356 + // If the incoming window is over half used, send an adjust.
357 + if (this.curInWindow > (this.maxInWindow / 2)) { SendChannelWindowAdjust(socket.ws, rcpt_chan, this.curInWindow); this.curInWindow = 0; }
358 });
359 } catch (e) {
360 Debug("Cannot forward data to downlink socket.");
@@ -406,17 +375,7 @@ function CreateAPFClient(parent, args) {
375 }
376
377 function parseChannelOpen(data) {
409 - var result = {
410 - len: 0, //to be filled later
411 - cmd: APFProtocol.CHANNEL_OPEN,
412 - chan_type: "", //to be filled later
413 - sender_chan: 0, //to be filled later
414 - window_size: 0, //to be filled later
415 - target_address: "", //to be filled later
416 - target_port: 0, //to be filled later
417 - origin_address: "", //to be filled later
418 - origin_port: 0, //to be filled later
419 - };
378 + var result = { cmd: APFProtocol.CHANNEL_OPEN };
379 var chan_type_slen = ReadInt(data, 1);
380 result.chan_type = data.substring(5, 5 + chan_type_slen);
381 result.sender_chan = ReadInt(data, 5 + chan_type_slen);
@@ -430,12 +389,14 @@ function CreateAPFClient(parent, args) {
389 result.len = 33 + chan_type_slen + c_len + o_len;
390 return result;
391 }
392 +
393 function SendChannelOpenFailure(socket, chan_data) {
394 var data = String.fromCharCode(APFProtocol.CHANNEL_OPEN_FAILURE) + IntToStr(chan_data.sender_chan)
395 + IntToStr(2) + IntToStr(0) + IntToStr(0);
396 socket.write(data);
397 Debug("APF: Send ChannelOpenFailure");
398 }
399 +
400 function SendChannelOpenConfirm(socket, chan_data) {
401 var data = String.fromCharCode(APFProtocol.CHANNEL_OPEN_CONFIRMATION) + IntToStr(chan_data.sender_chan)
402 + IntToStr(chan_data.sender_chan) + IntToStr(chan_data.window_size) + IntToStr(0xFFFFFFFF);
@@ -472,25 +433,18 @@ function CreateAPFClient(parent, args) {
433 }
434 obj.cirastate = CIRASTATE.INITIAL;
435 obj.pfwd_idx = 0;
475 -
436 +
437 //obj.forwardClient = new obj.ws(obj.args.mpsurl, obj.tlsoptions);
438 //obj.forwardClient.on("open", obj.onSecureConnect);
439
479 -
480 - var wsoptions = obj.http.parseUri(obj.args.mpsurl);
440 + var wsoptions = obj.http.parseUri(obj.args.mpsurl);
441 wsoptions.rejectUnauthorized = 0;
482 - obj.forwardClient = obj.http.request(wsoptions);
483 - obj.forwardClient.upgrade = obj.onSecureConnect;
442 + obj.forwardClient = obj.http.request(wsoptions);
443 + obj.forwardClient.upgrade = obj.onSecureConnect;
444 obj.forwardClient.end(); // end request, trigger completion of HTTP request
445 }
446
487 - obj.disconnect = function () {
488 - try {
489 - obj.forwardClient.ws.end();
490 - } catch (e) {
491 - Debug(e);
492 - }
493 - }
447 + obj.disconnect = function () { try { obj.forwardClient.ws.end(); } catch (e) { Debug(e); } }
448
449 return obj;
450 }
amtmanager.js
+2 -2
@@ -44,7 +44,7 @@ module.exports.CreateAmtManager = function(parent) {
44 // React to nodes connecting and disconnecting
45 if (event.action == 'nodeconnect') {
46 if ((event.conn & 14) != 0) { // connectType: Bitmask, 1 = MeshAgent, 2 = Intel AMT CIRA, 4 = Intel AMT local, 8 = Intel AMT Relay, 16 = MQTT
47 - //if ((event.conn & 2) == 0) return // Debug: Only look at CIRA connections *****************************
47 + //if ((event.conn & 2) == 0) return // Debug: Only look at CIRA connections
48
49 // We have an OOB connection to Intel AMT, update our information
50 var dev = obj.amtDevices[event.nodeid];
@@ -266,7 +266,7 @@ module.exports.CreateAmtManager = function(parent) {
266 }
267
268 function attemptLocalConnectResponse(stack, name, responses, status) {
269 - //console.log('attemptLocalConnectResponse', status);
269 + //console.log('attemptLocalConnectResponse', status, stack.dev.name);
270
271 // Release active connection to this host.
272 delete obj.activeLocalConnections[stack.wsman.comm.host];
apfserver.js deleted
-734
@@ -1,734 +0,0 @@
1 -/**
2 -* @description MeshCentral Intel(R) AMT APF over websocket server
3 -* @author Ylian Saint-Hilaire/Joko Sastriawan
4 -* @copyright Intel Corporation 2018-2020
5 -* @license Apache-2.0
6 -* @version v0.0.1
7 -*/
8 -
9 -/*jslint node: true */
10 -/*jshint node: true */
11 -/*jshint strict:false */
12 -/*jshint -W097 */
13 -/*jshint esversion: 6 */
14 -"use strict";
15 -
16 -// Construct a Intel AMT APF server object
17 -module.exports.CreateApfServer = function (parent, db, args) {
18 - var obj = {};
19 - obj.parent = parent;
20 - obj.db = db;
21 - obj.args = args;
22 - obj.apfConnections = {};
23 - const constants = (require('crypto').constants ? require('crypto').constants : require('constants')); // require('constants') is deprecated in Node 11.10, use require('crypto').constants instead.
24 - const common = require("./common.js");
25 - const net = require("net");
26 - const MAX_IDLE = 90000; // 90 seconds max idle time, higher than the typical KEEP-ALIVE periode of 60 seconds
27 -
28 -
29 - const APFProtocol = {
30 - UNKNOWN: 0,
31 - DISCONNECT: 1,
32 - SERVICE_REQUEST: 5,
33 - SERVICE_ACCEPT: 6,
34 - USERAUTH_REQUEST: 50,
35 - USERAUTH_FAILURE: 51,
36 - USERAUTH_SUCCESS: 52,
37 - GLOBAL_REQUEST: 80,
38 - REQUEST_SUCCESS: 81,
39 - REQUEST_FAILURE: 82,
40 - CHANNEL_OPEN: 90,
41 - CHANNEL_OPEN_CONFIRMATION: 91,
42 - CHANNEL_OPEN_FAILURE: 92,
43 - CHANNEL_WINDOW_ADJUST: 93,
44 - CHANNEL_DATA: 94,
45 - CHANNEL_CLOSE: 97,
46 - PROTOCOLVERSION: 192,
47 - KEEPALIVE_REQUEST: 208,
48 - KEEPALIVE_REPLY: 209,
49 - KEEPALIVE_OPTIONS_REQUEST: 210,
50 - KEEPALIVE_OPTIONS_REPLY: 211
51 - };
52 -
53 - /*
54 - const APFDisconnectCode = {
55 - HOST_NOT_ALLOWED_TO_CONNECT: 1,
56 - PROTOCOL_ERROR: 2,
57 - KEY_EXCHANGE_FAILED: 3,
58 - RESERVED: 4,
59 - MAC_ERROR: 5,
60 - COMPRESSION_ERROR: 6,
61 - SERVICE_NOT_AVAILABLE: 7,
62 - PROTOCOL_VERSION_NOT_SUPPORTED: 8,
63 - HOST_KEY_NOT_VERIFIABLE: 9,
64 - CONNECTION_LOST: 10,
65 - BY_APPLICATION: 11,
66 - TOO_MANY_CONNECTIONS: 12,
67 - AUTH_CANCELLED_BY_USER: 13,
68 - NO_MORE_AUTH_METHODS_AVAILABLE: 14,
69 - INVALID_CREDENTIALS: 15,
70 - CONNECTION_TIMED_OUT: 16,
71 - BY_POLICY: 17,
72 - TEMPORARILY_UNAVAILABLE: 18
73 - };
74 -
75 - const APFChannelOpenFailCodes = {
76 - ADMINISTRATIVELY_PROHIBITED: 1,
77 - CONNECT_FAILED: 2,
78 - UNKNOWN_CHANNEL_TYPE: 3,
79 - RESOURCE_SHORTAGE: 4,
80 - };
81 - */
82 -
83 - const APFChannelOpenFailureReasonCode = {
84 - AdministrativelyProhibited: 1,
85 - ConnectFailed: 2,
86 - UnknownChannelType: 3,
87 - ResourceShortage: 4,
88 - };
89 -
90 - // Stat counters
91 - var connectionCount = 0;
92 - var userAuthRequestCount = 0;
93 - var incorrectPasswordCount = 0;
94 - var meshNotFoundCount = 0;
95 - var unknownNodeCount = 0;
96 - var unknownMeshIdCount = 0;
97 - var addedDeviceCount = 0;
98 - var ciraTimeoutCount = 0;
99 - var protocolVersionCount = 0;
100 - var badUserNameLengthCount = 0;
101 - var channelOpenCount = 0;
102 - var channelOpenConfirmCount = 0;
103 - var channelOpenFailCount = 0;
104 - var channelCloseCount = 0;
105 - var disconnectCommandCount = 0;
106 - var socketClosedCount = 0;
107 - var socketErrorCount = 0;
108 - var maxDomainDevicesReached = 0;
109 -
110 - // Return statistics about this APF server
111 - obj.getStats = function () {
112 - return {
113 - apfConnections: Object.keys(obj.apfConnections).length,
114 - connectionCount: connectionCount,
115 - userAuthRequestCount: userAuthRequestCount,
116 - incorrectPasswordCount: incorrectPasswordCount,
117 - meshNotFoundCount: meshNotFoundCount,
118 - unknownNodeCount: unknownNodeCount,
119 - unknownMeshIdCount: unknownMeshIdCount,
120 - addedDeviceCount: addedDeviceCount,
121 - apfTimeoutCount: ciraTimeoutCount,
122 - protocolVersionCount: protocolVersionCount,
123 - badUserNameLengthCount: badUserNameLengthCount,
124 - channelOpenCount: channelOpenCount,
125 - channelOpenConfirmCount: channelOpenConfirmCount,
126 - channelOpenFailCount: channelOpenFailCount,
127 - channelCloseCount: channelCloseCount,
128 - disconnectCommandCount: disconnectCommandCount,
129 - socketClosedCount: socketClosedCount,
130 - socketErrorCount: socketErrorCount,
131 - maxDomainDevicesReached : maxDomainDevicesReached
132 - };
133 - }
134 -
135 - obj.onConnection = function(socket) {
136 - connectionCount++;
137 - // treat APS over WS like tlsoffload APF
138 - socket.tag = { first: true, clientCert: null, accumulator: "", activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
139 - parent.debug('apf', "New APF connection");
140 - parent.debug('apf',"WS Extensions:"+socket.extensions);
141 - parent.debug('apf',"WS Binary type:"+socket.binaryType);
142 -
143 - //socket._socket.on('data', function(chunk) { console.log(chunk.toString('hex'))});
144 -
145 - // Setup the APF keep alive timer
146 - // Websocket does not have timout
147 - // socket.setTimeout(MAX_IDLE);
148 - //socket.on("timeout", () => { ciraTimeoutCount++; parent.debug('apf', "APF timeout, disconnecting."); try { socket.terminate(); } catch (e) { } });
149 - //use on message instead because of websocket
150 - socket.on("message", function (data) {
151 - // use the same debug flag like APF
152 - if (obj.args.debug) { var buf = Buffer.from(data, "binary"); console.log("APF <-- (" + buf.length + "):" + buf.toString('hex')); } // Print out received bytes
153 - socket.tag.accumulator += data.toString("binary"); // append as binary string
154 -
155 -
156 - try {
157 - // Parse all of the APF data we can
158 - var l = 0;
159 - do { l = ProcessCommand(socket); if (l > 0) { socket.tag.accumulator = socket.tag.accumulator.substring(l); } } while (l > 0);
160 - if (l < 0) { socket.terminate(); }
161 - } catch (e) {
162 - console.log(e);
163 - }
164 - });
165 -
166 - // Process one AFP command
167 - function ProcessCommand(socket) {
168 - var cmd = socket.tag.accumulator.charCodeAt(0);
169 - var len = socket.tag.accumulator.length;
170 - var data = socket.tag.accumulator;
171 - if (len == 0) { return 0; }
172 -
173 - switch (cmd) {
174 - case APFProtocol.KEEPALIVE_REQUEST: {
175 - if (len < 5) return 0;
176 - parent.debug('apfcmd', 'KEEPALIVE_REQUEST');
177 - SendKeepAliveReply(socket, common.ReadInt(data, 1));
178 - return 5;
179 - }
180 - case APFProtocol.KEEPALIVE_REPLY: {
181 - if (len < 5) return 0;
182 - parent.debug('apfcmd', 'KEEPALIVE_REPLY');
183 - return 5;
184 - }
185 - case APFProtocol.PROTOCOLVERSION: {
186 - if (len < 93) return 0;
187 - protocolVersionCount++;
188 - socket.tag.MajorVersion = common.ReadInt(data, 1);
189 - socket.tag.MinorVersion = common.ReadInt(data, 5);
190 - socket.tag.SystemId = guidToStr(common.rstr2hex(data.substring(13, 29))).toLowerCase();
191 - parent.debug('apfcmd', 'PROTOCOLVERSION', socket.tag.MajorVersion, socket.tag.MinorVersion, socket.tag.SystemId);
192 - return 93;
193 - }
194 - case APFProtocol.USERAUTH_REQUEST: {
195 - if (len < 13) return 0;
196 - userAuthRequestCount++;
197 - var usernameLen = common.ReadInt(data, 1);
198 - var username = data.substring(5, 5 + usernameLen);
199 - var serviceNameLen = common.ReadInt(data, 5 + usernameLen);
200 - var serviceName = data.substring(9 + usernameLen, 9 + usernameLen + serviceNameLen);
201 - var methodNameLen = common.ReadInt(data, 9 + usernameLen + serviceNameLen);
202 - var methodName = data.substring(13 + usernameLen + serviceNameLen, 13 + usernameLen + serviceNameLen + methodNameLen);
203 - var passwordLen = 0, password = null;
204 - if (methodName == 'password') {
205 - passwordLen = common.ReadInt(data, 14 + usernameLen + serviceNameLen + methodNameLen);
206 - password = data.substring(18 + usernameLen + serviceNameLen + methodNameLen, 18 + usernameLen + serviceNameLen + methodNameLen + passwordLen);
207 - }
208 - //console.log('APF:USERAUTH_REQUEST user=' + username + ', service=' + serviceName + ', method=' + methodName + ', password=' + password);
209 - parent.debug('apfcmd', 'USERAUTH_REQUEST user=' + username + ', service=' + serviceName + ', method=' + methodName + ', password=' + password);
210 -
211 - // Check the APF password
212 - if ((args.mpspass != null) && (password != args.mpspass)) { incorrectPasswordCount++; parent.debug('apf', 'Incorrect password', username, password); SendUserAuthFail(socket); return -1; }
213 -
214 - // Check the APF username, which should be the start of the MeshID.
215 - if (usernameLen != 16) { badUserNameLengthCount++; parent.debug('apf', 'Username length not 16', username, password); SendUserAuthFail(socket); return -1; }
216 - var meshIdStart = '/' + username, mesh = null;
217 - if (obj.parent.webserver.meshes) { for (var i in obj.parent.webserver.meshes) { if (obj.parent.webserver.meshes[i]._id.replace(/\@/g, 'X').replace(/\$/g, 'X').indexOf(meshIdStart) > 0) { mesh = obj.parent.webserver.meshes[i]; break; } } }
218 - if (mesh == null) { meshNotFoundCount++; parent.debug('apf', 'Mesh not found', username, password); SendUserAuthFail(socket); return -1; }
219 -
220 - // If this is a agent-less mesh, use the device guid 3 times as ID.
221 - if (mesh.mtype == 1) {
222 - // Intel AMT GUID (socket.tag.SystemId) will be used as NodeID
223 - var systemid = socket.tag.SystemId.split('-').join('');
224 - var nodeid = Buffer.from(systemid + systemid + systemid, 'hex').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
225 - var domain = obj.parent.config.domains[mesh.domain];
226 - socket.tag.domain = domain;
227 - socket.tag.domainid = mesh.domain;
228 - socket.tag.name = '';
229 - socket.tag.nodeid = 'node/' + mesh.domain + '/' + nodeid; // Turn 16bit systemid guid into 48bit nodeid that is base64 encoded
230 - socket.tag.meshid = mesh._id;
231 - socket.tag.connectTime = Date.now();
232 -
233 - obj.db.Get(socket.tag.nodeid, function (err, nodes) {
234 - if ((nodes == null) || (nodes.length !== 1)) {
235 - // Check if we already have too many devices for this domain
236 - if (domain.limits && (typeof domain.limits.maxdevices == 'number')) {
237 - db.isMaxType(domain.limits.maxdevices, 'node', mesh.domain, function (ismax, count) {
238 - if (ismax == true) {
239 - // Too many devices in this domain.
240 - maxDomainDevicesReached++;
241 - console.log('Too many devices on this domain to accept the APF connection. meshid: ' + socket.tag.meshid);
242 - socket.terminate();
243 - } else {
244 - // We are under the limit, create the new device.
245 - // Node is not in the database, add it. Credentials will be empty until added by the user.
246 - var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: mesh.domain, intelamt: { user: '', pass: '', tls: 0, state: 2 } };
247 - obj.db.Set(device);
248 -
249 - // Event the new node
250 - addedDeviceCount++;
251 - var change = 'APF added device ' + socket.tag.name + ' to group ' + mesh.name;
252 - obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: parent.webserver.CloneSafeNode(device), msg: change, domain: mesh.domain });
253 -
254 - // Add the connection to the APF connection list
255 - obj.apfConnections[socket.tag.nodeid] = socket;
256 - // send connectivuty update type 8 for APF
257 - obj.parent.SetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, 8, 7); // TODO: Right now report power state as "present" (7) until we can poll.
258 - SendUserAuthSuccess(socket); // Notify the auth success on the APF connection
259 - }
260 - });
261 - return;
262 - } else {
263 - // Node is not in the database, add it. Credentials will be empty until added by the user.
264 - var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: mesh.domain, intelamt: { user: '', pass: '', tls: 0, state: 2 } };
265 - obj.db.Set(device);
266 -
267 - // Event the new node
268 - addedDeviceCount++;
269 - var change = 'APF added device ' + socket.tag.name + ' to group ' + mesh.name;
270 - obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: parent.webserver.CloneSafeNode(device), msg: change, domain: mesh.domain });
271 - }
272 - } else {
273 - // Node is already present
274 - var node = nodes[0];
275 - if ((node.intelamt != null) && (node.intelamt.state == 2)) { socket.tag.host = node.intelamt.host; }
276 - }
277 -
278 - // Add the connection to the APF connection list
279 - obj.apfConnections[socket.tag.nodeid] = socket;
280 - obj.parent.SetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, 8, 7); // TODO: Right now report power state as "present" (7) until we can poll.
281 - SendUserAuthSuccess(socket); // Notify the auth success on the APF connection
282 - });
283 - } else if (mesh.mtype == 2) { // If this is a agent mesh, search the mesh for this device UUID
284 - // Intel AMT GUID (socket.tag.SystemId) will be used to search the node
285 - obj.db.getAmtUuidNode(socket.tag.SystemId, function (err, nodes) { // TODO: May need to optimize this request with indexes
286 - if ((nodes == null) || (nodes.length !== 1)) {
287 - // New APF connection for unknown node, disconnect.
288 - unknownNodeCount++;
289 - console.log('APF connection for unknown node. groupid: ' + mesh._id + ', uuid: ' + socket.tag.SystemId);
290 - socket.terminate();
291 - return;
292 - }
293 -
294 - // Node is present
295 - var node = nodes[0];
296 - if ((node.intelamt != null) && (node.intelamt.state == 2)) { socket.tag.host = node.intelamt.host; }
297 - socket.tag.nodeid = node._id;
298 - socket.tag.meshid = mesh._id;
299 - socket.tag.connectTime = Date.now();
300 -
301 - // Add the connection to the APF connection list
302 - obj.apfConnections[socket.tag.nodeid] = socket;
303 - obj.parent.SetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, 8, 7); // TODO: Right now report power state as "present" (7) until we can poll.
304 - SendUserAuthSuccess(socket); // Notify the auth success on the APF connection
305 - });
306 - } else { // Unknown mesh type
307 - // New APF connection for unknown node, disconnect.
308 - unknownMeshIdCount++;
309 - console.log('APF connection to a unknown group type. groupid: ' + socket.tag.meshid);
310 - socket.terminate();
311 - return;
312 - }
313 - return 18 + usernameLen + serviceNameLen + methodNameLen + passwordLen;
314 - }
315 - case APFProtocol.SERVICE_REQUEST: {
316 - if (len < 5) return 0;
317 - var xserviceNameLen = common.ReadInt(data, 1);
318 - if (len < 5 + xserviceNameLen) return 0;
319 - var xserviceName = data.substring(5, 5 + xserviceNameLen);
320 - parent.debug('apfcmd', 'SERVICE_REQUEST', xserviceName);
321 - if (xserviceName == "pfwd@amt.intel.com") { SendServiceAccept(socket, "pfwd@amt.intel.com"); }
322 - if (xserviceName == "auth@amt.intel.com") { SendServiceAccept(socket, "auth@amt.intel.com"); }
323 - return 5 + xserviceNameLen;
324 - }
325 - case APFProtocol.GLOBAL_REQUEST: {
326 - if (len < 14) return 0;
327 - var requestLen = common.ReadInt(data, 1);
328 - if (len < 14 + requestLen) return 0;
329 - var request = data.substring(5, 5 + requestLen);
330 - //var wantResponse = data.charCodeAt(5 + requestLen);
331 -
332 - if (request == "tcpip-forward") {
333 - var addrLen = common.ReadInt(data, 6 + requestLen);
334 - if (len < 14 + requestLen + addrLen) return 0;
335 - var addr = data.substring(10 + requestLen, 10 + requestLen + addrLen);
336 - var port = common.ReadInt(data, 10 + requestLen + addrLen);
337 - parent.debug('apfcmd', 'GLOBAL_REQUEST', request, addr + ':' + port);
338 - ChangeHostname(socket, addr, socket.tag.SystemId);
339 - if (socket.tag.boundPorts.indexOf(port) == -1) { socket.tag.boundPorts.push(port); }
340 - SendTcpForwardSuccessReply(socket, port);
341 - return 14 + requestLen + addrLen;
342 - }
343 -
344 - if (request == "cancel-tcpip-forward") {
345 - var addrLen = common.ReadInt(data, 6 + requestLen);
346 - if (len < 14 + requestLen + addrLen) return 0;
347 - var addr = data.substring(10 + requestLen, 10 + requestLen + addrLen);
348 - var port = common.ReadInt(data, 10 + requestLen + addrLen);
349 - parent.debug('apfcmd', 'GLOBAL_REQUEST', request, addr + ':' + port);
350 - var portindex = socket.tag.boundPorts.indexOf(port);
351 - if (portindex >= 0) { socket.tag.boundPorts.splice(portindex, 1); }
352 - SendTcpForwardCancelReply(socket);
353 - return 14 + requestLen + addrLen;
354 - }
355 -
356 - if (request == "udp-send-to@amt.intel.com") {
357 - var addrLen = common.ReadInt(data, 6 + requestLen);
358 - if (len < 26 + requestLen + addrLen) return 0;
359 - var addr = data.substring(10 + requestLen, 10 + requestLen + addrLen);
360 - var port = common.ReadInt(data, 10 + requestLen + addrLen);
361 - var oaddrLen = common.ReadInt(data, 14 + requestLen + addrLen);
362 - if (len < 26 + requestLen + addrLen + oaddrLen) return 0;
363 - var oaddr = data.substring(18 + requestLen, 18 + requestLen + addrLen);
364 - var oport = common.ReadInt(data, 18 + requestLen + addrLen + oaddrLen);
365 - var datalen = common.ReadInt(data, 22 + requestLen + addrLen + oaddrLen);
366 - if (len < 26 + requestLen + addrLen + oaddrLen + datalen) return 0;
367 - parent.debug('apfcmd', 'GLOBAL_REQUEST', request, addr + ':' + port, oaddr + ':' + oport, datalen);
368 - // TODO
369 - return 26 + requestLen + addrLen + oaddrLen + datalen;
370 - }
371 -
372 - return 6 + requestLen;
373 - }
374 - case APFProtocol.CHANNEL_OPEN: {
375 - if (len < 33) return 0;
376 - var ChannelTypeLength = common.ReadInt(data, 1);
377 - if (len < (33 + ChannelTypeLength)) return 0;
378 -
379 - // Decode channel identifiers and window size
380 - var ChannelType = data.substring(5, 5 + ChannelTypeLength);
381 - var SenderChannel = common.ReadInt(data, 5 + ChannelTypeLength);
382 - var WindowSize = common.ReadInt(data, 9 + ChannelTypeLength);
383 -
384 - // Decode the target
385 - var TargetLen = common.ReadInt(data, 17 + ChannelTypeLength);
386 - if (len < (33 + ChannelTypeLength + TargetLen)) return 0;
387 - var Target = data.substring(21 + ChannelTypeLength, 21 + ChannelTypeLength + TargetLen);
388 - var TargetPort = common.ReadInt(data, 21 + ChannelTypeLength + TargetLen);
389 -
390 - // Decode the source
391 - var SourceLen = common.ReadInt(data, 25 + ChannelTypeLength + TargetLen);
392 - if (len < (33 + ChannelTypeLength + TargetLen + SourceLen)) return 0;
393 - var Source = data.substring(29 + ChannelTypeLength + TargetLen, 29 + ChannelTypeLength + TargetLen + SourceLen);
394 - var SourcePort = common.ReadInt(data, 29 + ChannelTypeLength + TargetLen + SourceLen);
395 -
396 - channelOpenCount++;
397 - parent.debug('apfcmd', 'CHANNEL_OPEN', ChannelType, SenderChannel, WindowSize, Target + ':' + TargetPort, Source + ':' + SourcePort);
398 -
399 - // Check if we understand this channel type
400 - //if (ChannelType.toLowerCase() == "direct-tcpip")
401 - {
402 - // We don't understand this channel type, send an error back
403 - SendChannelOpenFailure(socket, SenderChannel, APFChannelOpenFailureReasonCode.UnknownChannelType);
404 - return 33 + ChannelTypeLength + TargetLen + SourceLen;
405 - }
406 -
407 - /*
408 - // This is a correct connection. Lets get it setup
409 - var MeshAmtEventEndpoint = { ServerChannel: GetNextBindId(), AmtChannel: SenderChannel, MaxWindowSize: 2048, CurrentWindowSize:2048, SendWindow: WindowSize, InfoHeader: "Target: " + Target + ":" + TargetPort + ", Source: " + Source + ":" + SourcePort};
410 - // TODO: Connect this socket for a WSMAN event
411 - SendChannelOpenConfirmation(socket, SenderChannel, MeshAmtEventEndpoint.ServerChannel, MeshAmtEventEndpoint.MaxWindowSize);
412 - */
413 -
414 - return 33 + ChannelTypeLength + TargetLen + SourceLen;
415 - }
416 - case APFProtocol.CHANNEL_OPEN_CONFIRMATION:
417 - {
418 - if (len < 17) return 0;
419 - var RecipientChannel = common.ReadInt(data, 1);
420 - var SenderChannel = common.ReadInt(data, 5);
421 - var WindowSize = common.ReadInt(data, 9);
422 - socket.tag.activetunnels++;
423 - var cirachannel = socket.tag.channels[RecipientChannel];
424 - if (cirachannel == null) { /*console.log("APF Error in CHANNEL_OPEN_CONFIRMATION: Unable to find channelid " + RecipientChannel);*/ return 17; }
425 - cirachannel.amtchannelid = SenderChannel;
426 - cirachannel.sendcredits = cirachannel.amtCiraWindow = WindowSize;
427 - channelOpenConfirmCount++;
428 - parent.debug('apfcmd', 'CHANNEL_OPEN_CONFIRMATION', RecipientChannel, SenderChannel, WindowSize);
429 - if (cirachannel.closing == 1) {
430 - // Close this channel
431 - SendChannelClose(cirachannel.socket, cirachannel.amtchannelid);
432 - } else {
433 - cirachannel.state = 2;
434 - // Send any pending data
435 - if (cirachannel.sendBuffer != null) {
436 - if (cirachannel.sendBuffer.length <= cirachannel.sendcredits) {
437 - // Send the entire pending buffer
438 - SendChannelData(cirachannel.socket, cirachannel.amtchannelid, cirachannel.sendBuffer);
439 - cirachannel.sendcredits -= cirachannel.sendBuffer.length;
440 - delete cirachannel.sendBuffer;
441 - if (cirachannel.onSendOk) { cirachannel.onSendOk(cirachannel); }
442 - } else {
443 - // Send a part of the pending buffer
444 - SendChannelData(cirachannel.socket, cirachannel.amtchannelid, cirachannel.sendBuffer.substring(0, cirachannel.sendcredits));
445 - cirachannel.sendBuffer = cirachannel.sendBuffer.substring(cirachannel.sendcredits);
446 - cirachannel.sendcredits = 0;
447 - }
448 - }
449 - // Indicate the channel is open
450 - if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
451 - }
452 - return 17;
453 - }
454 - case APFProtocol.CHANNEL_OPEN_FAILURE:
455 - {
456 - if (len < 17) return 0;
457 - var RecipientChannel = common.ReadInt(data, 1);
458 - var ReasonCode = common.ReadInt(data, 5);
459 - channelOpenFailCount++;
460 - parent.debug('apfcmd', 'CHANNEL_OPEN_FAILURE', RecipientChannel, ReasonCode);
461 - var cirachannel = socket.tag.channels[RecipientChannel];
462 - if (cirachannel == null) { console.log("APF Error in CHANNEL_OPEN_FAILURE: Unable to find channelid " + RecipientChannel); return 17; }
463 - if (cirachannel.state > 0) {
464 - cirachannel.state = 0;
465 - if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
466 - delete socket.tag.channels[RecipientChannel];
467 - }
468 - return 17;
469 - }
470 - case APFProtocol.CHANNEL_CLOSE:
471 - {
472 - if (len < 5) return 0;
473 - var RecipientChannel = common.ReadInt(data, 1);
474 - channelCloseCount++;
475 - parent.debug('apfcmd', 'CHANNEL_CLOSE', RecipientChannel);
476 - var cirachannel = socket.tag.channels[RecipientChannel];
477 - if (cirachannel == null) { console.log("APF Error in CHANNEL_CLOSE: Unable to find channelid " + RecipientChannel); return 5; }
478 - socket.tag.activetunnels--;
479 - if (cirachannel.state > 0) {
480 - cirachannel.state = 0;
481 - if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
482 - SendChannelClose(cirachannel.socket, cirachannel.amtchannelid);
483 - delete socket.tag.channels[RecipientChannel];
484 - }
485 - return 5;
486 - }
487 - case APFProtocol.CHANNEL_WINDOW_ADJUST:
488 - {
489 - if (len < 9) return 0;
490 - var RecipientChannel = common.ReadInt(data, 1);
491 - var ByteToAdd = common.ReadInt(data, 5);
492 - var cirachannel = socket.tag.channels[RecipientChannel];
493 - if (cirachannel == null) { console.log("APF Error in CHANNEL_WINDOW_ADJUST: Unable to find channelid " + RecipientChannel); return 9; }
494 - cirachannel.sendcredits += ByteToAdd;
495 - parent.debug('apfcmd', 'CHANNEL_WINDOW_ADJUST', RecipientChannel, ByteToAdd, cirachannel.sendcredits);
496 - if (cirachannel.state == 2 && cirachannel.sendBuffer != null) {
497 - // Compute how much data we can send
498 - if (cirachannel.sendBuffer.length <= cirachannel.sendcredits) {
499 - // Send the entire pending buffer
500 - SendChannelData(cirachannel.socket, cirachannel.amtchannelid, cirachannel.sendBuffer);
501 - cirachannel.sendcredits -= cirachannel.sendBuffer.length;
502 - delete cirachannel.sendBuffer;
503 - if (cirachannel.onSendOk) { cirachannel.onSendOk(cirachannel); }
504 - } else {
505 - // Send a part of the pending buffer
506 - SendChannelData(cirachannel.socket, cirachannel.amtchannelid, cirachannel.sendBuffer.substring(0, cirachannel.sendcredits));
507 - cirachannel.sendBuffer = cirachannel.sendBuffer.substring(cirachannel.sendcredits);
508 - cirachannel.sendcredits = 0;
509 - }
510 - }
511 - return 9;
512 - }
513 - case APFProtocol.CHANNEL_DATA:
514 - {
515 - if (len < 9) return 0;
516 - var RecipientChannel = common.ReadInt(data, 1);
517 - var LengthOfData = common.ReadInt(data, 5);
518 - if (len < (9 + LengthOfData)) return 0;
519 - parent.debug('apfcmddata', 'CHANNEL_DATA', RecipientChannel, LengthOfData);
520 - var cirachannel = socket.tag.channels[RecipientChannel];
521 - if (cirachannel == null) { console.log("APF Error in CHANNEL_DATA: Unable to find channelid " + RecipientChannel); return 9 + LengthOfData; }
522 - cirachannel.amtpendingcredits += LengthOfData;
523 - if (cirachannel.onData) cirachannel.onData(cirachannel, data.substring(9, 9 + LengthOfData));
524 - if (cirachannel.amtpendingcredits > (cirachannel.ciraWindow / 2)) {
525 - SendChannelWindowAdjust(cirachannel.socket, cirachannel.amtchannelid, cirachannel.amtpendingcredits); // Adjust the buffer window
526 - cirachannel.amtpendingcredits = 0;
527 - }
528 - return 9 + LengthOfData;
529 - }
530 - case APFProtocol.DISCONNECT:
531 - {
532 - if (len < 7) return 0;
533 - var ReasonCode = common.ReadInt(data, 1);
534 - disconnectCommandCount++;
535 - parent.debug('apfcmd', 'DISCONNECT', ReasonCode);
536 - try { delete obj.apfConnections[socket.tag.nodeid]; } catch (e) { }
537 - obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 8);
538 - return 7;
539 - }
540 - default:
541 - {
542 - parent.debug('apfcmd', 'Unknown APF command: ' + cmd);
543 - return -1;
544 - }
545 - }
546 - }
547 -
548 - socket.addListener("close", function () {
549 - socketClosedCount++;
550 - parent.debug('apf', 'APF connection closed');
551 - try { delete obj.apfConnections[socket.tag.nodeid]; } catch (e) { }
552 - obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 8);
553 - });
554 -
555 - socket.addListener("error", function (e) {
556 - socketErrorCount++;
557 - console.log("APF Error: " + e);
558 - });
559 -
560 - }
561 -
562 - // Disconnect APF tunnel
563 - obj.close = function (socket) {
564 - try { socket.terminate(); } catch (e) { }
565 - try { delete obj.apfConnections[socket.tag.nodeid]; } catch (e) { }
566 - obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 8);
567 - };
568 -
569 - function SendServiceAccept(socket, service) {
570 - Write(socket, String.fromCharCode(APFProtocol.SERVICE_ACCEPT) + common.IntToStr(service.length) + service);
571 - }
572 -
573 - function SendTcpForwardSuccessReply(socket, port) {
574 - Write(socket, String.fromCharCode(APFProtocol.REQUEST_SUCCESS) + common.IntToStr(port));
575 - }
576 -
577 - function SendTcpForwardCancelReply(socket) {
578 - Write(socket, String.fromCharCode(APFProtocol.REQUEST_SUCCESS));
579 - }
580 -
581 - /*
582 - function SendKeepAliveRequest(socket, cookie) {
583 - Write(socket, String.fromCharCode(APFProtocol.KEEPALIVE_REQUEST) + common.IntToStr(cookie));
584 - }
585 - */
586 -
587 - function SendKeepAliveReply(socket, cookie) {
588 - Write(socket, String.fromCharCode(APFProtocol.KEEPALIVE_REPLY) + common.IntToStr(cookie));
589 - }
590 -
591 - function SendChannelOpenFailure(socket, senderChannel, reasonCode) {
592 - Write(socket, String.fromCharCode(APFProtocol.CHANNEL_OPEN_FAILURE) + common.IntToStr(senderChannel) + common.IntToStr(reasonCode) + common.IntToStr(0) + common.IntToStr(0));
593 - }
594 -
595 - /*
596 - function SendChannelOpenConfirmation(socket, recipientChannelId, senderChannelId, initialWindowSize) {
597 - Write(socket, String.fromCharCode(APFProtocol.CHANNEL_OPEN_CONFIRMATION) + common.IntToStr(recipientChannelId) + common.IntToStr(senderChannelId) + common.IntToStr(initialWindowSize) + common.IntToStr(-1));
598 - }
599 - */
600 -
601 - function SendChannelOpen(socket, direct, channelid, windowsize, target, targetport, source, sourceport) {
602 - var connectionType = ((direct == true) ? "direct-tcpip" : "forwarded-tcpip");
603 - if ((target == null) || (target == null)) target = ''; // TODO: Reports of target being undefined that causes target.length to fail. This is a hack.
604 - Write(socket, String.fromCharCode(APFProtocol.CHANNEL_OPEN) + common.IntToStr(connectionType.length) + connectionType + common.IntToStr(channelid) + common.IntToStr(windowsize) + common.IntToStr(-1) + common.IntToStr(target.length) + target + common.IntToStr(targetport) + common.IntToStr(source.length) + source + common.IntToStr(sourceport));
605 - }
606 -
607 - function SendChannelClose(socket, channelid) {
608 - Write(socket, String.fromCharCode(APFProtocol.CHANNEL_CLOSE) + common.IntToStr(channelid));
609 - }
610 -
611 - function SendChannelData(socket, channelid, data) {
612 - Write(socket, String.fromCharCode(APFProtocol.CHANNEL_DATA) + common.IntToStr(channelid) + common.IntToStr(data.length) + data);
613 - }
614 -
615 - function SendChannelWindowAdjust(socket, channelid, bytestoadd) {
616 - parent.debug('apfcmd', 'SendChannelWindowAdjust', channelid, bytestoadd);
617 - Write(socket, String.fromCharCode(APFProtocol.CHANNEL_WINDOW_ADJUST) + common.IntToStr(channelid) + common.IntToStr(bytestoadd));
618 - }
619 -
620 - /*
621 - function SendDisconnect(socket, reasonCode) {
622 - Write(socket, String.fromCharCode(APFProtocol.DISCONNECT) + common.IntToStr(reasonCode) + common.ShortToStr(0));
623 - }
624 - */
625 -
626 - function SendUserAuthFail(socket) {
627 - Write(socket, String.fromCharCode(APFProtocol.USERAUTH_FAILURE) + common.IntToStr(8) + 'password' + common.ShortToStr(0));
628 - }
629 -
630 - function SendUserAuthSuccess(socket) {
631 - Write(socket, String.fromCharCode(APFProtocol.USERAUTH_SUCCESS));
632 - }
633 -
634 - function Write(socket, data) {
635 - if (obj.args.debug) {
636 - // Print out sent bytes
637 - var buf = Buffer.from(data, "binary");
638 - console.log('APF --> (' + buf.length + '):' + buf.toString('hex'));
639 - socket.send(buf);
640 - } else {
641 - socket.send(Buffer.from(data, "binary"));
642 - }
643 - }
644 -
645 - // Setup a new channel to a nodeid
646 - obj.SetupChannelToNode = function (nodeid, targetport) {
647 - var apfconn = obj.apfConnections[nodeid];
648 - if (apfconn == null) return null;
649 - return obj.SetupChannel(apfconn, targetport);
650 - }
651 -
652 - obj.SetupChannel = function (socket, targetport) {
653 - var sourceport = (socket.tag.nextsourceport++ % 30000) + 1024;
654 - var cirachannel = { targetport: targetport, channelid: socket.tag.nextchannelid++, socket: socket, state: 1, sendcredits: 0, amtpendingcredits: 0, amtCiraWindow: 0, ciraWindow: 32768 };
655 - SendChannelOpen(socket, false, cirachannel.channelid, cirachannel.ciraWindow, socket.tag.host, targetport, "1.2.3.4", sourceport);
656 -
657 - // This function writes data to this APF channel
658 - cirachannel.write = function (data) {
659 - if (cirachannel.state == 0) return false;
660 - if (cirachannel.state == 1 || cirachannel.sendcredits == 0 || cirachannel.sendBuffer != null) {
661 - // Channel is connected, but we are out of credits. Add the data to the outbound buffer.
662 - if (cirachannel.sendBuffer == null) { cirachannel.sendBuffer = data; } else { cirachannel.sendBuffer += data; }
663 - return true;
664 - }
665 - // Compute how much data we can send
666 - if (data.length <= cirachannel.sendcredits) {
667 - // Send the entire message
668 - SendChannelData(cirachannel.socket, cirachannel.amtchannelid, data);
669 - cirachannel.sendcredits -= data.length;
670 - return true;
671 - }
672 - // Send a part of the message
673 - cirachannel.sendBuffer = data.substring(cirachannel.sendcredits);
674 - SendChannelData(cirachannel.socket, cirachannel.amtchannelid, data.substring(0, cirachannel.sendcredits));
675 - cirachannel.sendcredits = 0;
676 - return false;
677 - };
678 -
679 - // This function closes this APF channel
680 - cirachannel.close = function () {
681 - if (cirachannel.state == 0 || cirachannel.closing == 1) return;
682 - if (cirachannel.state == 1) { cirachannel.closing = 1; cirachannel.state = 0; if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); } return; }
683 - cirachannel.state = 0;
684 - cirachannel.closing = 1;
685 - SendChannelClose(cirachannel.socket, cirachannel.amtchannelid);
686 - if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
687 - };
688 -
689 - socket.tag.channels[cirachannel.channelid] = cirachannel;
690 - return cirachannel;
691 - };
692 -
693 - function ChangeHostname(socket, host, systemid) {
694 - if (socket.tag.host === host) return; // Nothing to change
695 - socket.tag.host = host;
696 -
697 - // Change the device
698 - obj.db.Get(socket.tag.nodeid, function (err, nodes) {
699 - if ((nodes == null) || (nodes.length !== 1)) return;
700 - var node = nodes[0];
701 -
702 - // See if any changes need to be made
703 - if ((node.intelamt != null) && (node.intelamt.host == host) && (node.name != null) && (node.name != '') && (node.intelamt.state == 2)) return;
704 -
705 - // Get the mesh for this device
706 - obj.db.Get(node.meshid, function (err, meshes) {
707 - if ((meshes == null) || (meshes.length !== 1)) return;
708 - var mesh = meshes[0];
709 -
710 - // Ready the node change event
711 - var changes = ['host'], event = { etype: 'node', action: 'changenode', nodeid: node._id };
712 - event.msg = +": ";
713 -
714 - // Make the change & save
715 - if (node.intelamt == null) node.intelamt = {};
716 - node.intelamt.host = host;
717 - node.intelamt.state = 2; // TODO: this is not real AMT state
718 - if (((node.name == null) || (node.name == '')) && (host != null) && (host != '')) { node.name = host.split('.')[0]; } // If this system has no name, set it to the start of the domain name.
719 - if (((node.name == null) || (node.name == '')) && (systemid != null)) { node.name = systemid; } // If this system still has no name, set it to the system GUID.
720 - obj.db.Set(node);
721 -
722 - // Event the node change
723 - event.msg = 'APF changed device ' + node.name + ' from group ' + mesh.name + ': ' + changes.join(', ');
724 - event.node = parent.webserver.CloneSafeNode(node);
725 - if (obj.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
726 - obj.parent.DispatchEvent(['*', node.meshid], obj, event);
727 - });
728 - });
729 - }
730 -
731 - function guidToStr(g) { return g.substring(6, 8) + g.substring(4, 6) + g.substring(2, 4) + g.substring(0, 2) + "-" + g.substring(10, 12) + g.substring(8, 10) + "-" + g.substring(14, 16) + g.substring(12, 14) + "-" + g.substring(16, 20) + "-" + g.substring(20); }
732 -
733 - return obj;
734 -};
meshagent.js
+1 -1
@@ -1475,7 +1475,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1475
1476 // Change the current core information string and event it
1477 function ChangeAgentCoreInfo(command) {
1478 - if (obj.agentInfo.capabilities & 0x40) return;
1478 + if ((obj.agentInfo == null) || (obj.agentInfo.capabilities & 0x40)) return;
1479 if ((command == null) || (command == null)) return; // Safety, should never happen.
1480
1481 // If the device is pending a change, hold.
meshcentral.js
-4
@@ -26,7 +26,6 @@ function CreateMeshCentralServer(config, args) {
26 obj.webserver = null;
27 obj.redirserver = null;
28 obj.mpsserver = null;
29 - obj.apfserver = null;
29 obj.mqttbroker = null;
30 obj.swarmserver = null;
31 obj.mailserver = null;
@@ -1318,9 +1317,6 @@ function CreateMeshCentralServer(config, args) {
1317 if ((obj.args.sessiontime != null) && ((typeof obj.args.sessiontime != 'number') || (obj.args.sessiontime < 1))) { delete obj.args.sessiontime; }
1318 if (!obj.args.sessionkey) { obj.args.sessionkey = buf.toString('hex').toUpperCase(); }
1319
1321 - // Create APF server to hook into webserver
1322 - obj.apfserver = require('./apfserver.js').CreateApfServer(obj, obj.db, obj.args);
1323 -
1320 // Create MQTT Broker to hook into webserver and mpsserver
1321 if ((typeof obj.config.settings.mqtt == 'object') && (typeof obj.config.settings.mqtt.auth == 'object') && (typeof obj.config.settings.mqtt.auth.keyid == 'string') && (typeof obj.config.settings.mqtt.auth.key == 'string')) { obj.mqttbroker = require("./mqttbroker.js").CreateMQTTBroker(obj, obj.db, obj.args); }
1322
meshuser.js
+4 -1
@@ -4670,9 +4670,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4670 if ((state == null) || (state.connectivity & 4) == 0) break;
4671 } else if (command.mode == 2) {
4672 if (parent.parent.mpsserver.ciraConnections[command.nodeid] == null) break;
4673 - } else if (command.mode == 3) {
4673 + }
4674 + /*
4675 + else if (command.mode == 3) {
4676 if (parent.parent.apfserver.apfConnections[command.nodeid] == null) break;
4677 }
4678 + */
4679
4680 // Get the node and the rights for this node
4681 parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
mpsserver.js
+420 -386
@@ -144,11 +144,13 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
144
145 // Delay setting the connectivity state by 300ms to allow time for CIRA port mappings to be established
146 // Report power state as "present" (7) until Intel AMT manager starts polling for power state.
147 - function delayedSetConnectivityState(meshid, nodeid, connectTime) {
148 - var f = function setConnFunc() { if (obj.ciraConnections[setConnFunc.nodeid] != null) { obj.parent.SetConnectivityState(setConnFunc.meshid, setConnFunc.nodeid, setConnFunc.connectTime, 2, 7); } }
147 + function delayedSetConnectivityState(meshid, nodeid, connectTime, connType) {
148 + if (nodeid.startsWith('*')) return; // Don't set connectivity state for Intel AMT self agent relay
149 + var f = function setConnFunc() { if (obj.ciraConnections[setConnFunc.nodeid] != null) { obj.parent.SetConnectivityState(setConnFunc.meshid, setConnFunc.nodeid, setConnFunc.connectTime, setConnFunc.connType, 7); } }
150 f.nodeid = nodeid;
151 f.meshid = meshid;
152 f.connectTime = connectTime;
153 + f.connType = connType;
154 setTimeout(f, 300);
155 }
156
@@ -220,13 +222,47 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
222 return packet_len;
223 }
224
225 + obj.onWebSocketConnection = function (socket) {
226 + connectionCount++;
227 + // connType: 2 = CIRA, 8 = Relay
228 + socket.tag = { first: true, connType: 2, clientCert: null, accumulator: '', activetunnels: 0, boundPorts: [], websocket: true, socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
229 + socket.websocket = 1;
230 + parent.debug('mps', "New CIRA websocket connection");
231 +
232 + socket.on('message', function (data) {
233 + if (args.mpsdebug) { var buf = Buffer.from(data, 'binary'); console.log("MPS <-- (" + buf.length + "):" + buf.toString('hex')); } // Print out received bytes
234 + this.tag.accumulator += data.toString('binary'); // Append as binary string
235 + try {
236 + // Parse all of the APF data we can
237 + var l = 0;
238 + do { l = ProcessCommand(this); if (l > 0) { this.tag.accumulator = this.tag.accumulator.substring(l); } } while (l > 0);
239 + if (l < 0) { this.terminate(); }
240 + } catch (e) {
241 + console.log(e);
242 + }
243 + });
244 +
245 + socket.addListener('close', function () {
246 + socketClosedCount++;
247 + parent.debug('mps', "CIRA websocket closed", this.tag.meshid, this.tag.nodeid);
248 + try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
249 + if (!this.tag.nodeid.startsWith('*')) { obj.parent.ClearConnectivityState(this.tag.meshid, this.tag.nodeid, this.tag.connType); }
250 + });
251 +
252 + socket.addListener('error', function (e) {
253 + socketErrorCount++;
254 + parent.debug('mps', "CIRA websocket connection error", e);
255 + });
256 + }
257 +
258 // Called when a new TLS/TCP connection is accepted
259 function onConnection(socket) {
260 connectionCount++;
261 + // connType: 2 = CIRA, 8 = Relay
262 if (obj.args.mpstlsoffload) {
227 - socket.tag = { first: true, clientCert: null, accumulator: '', activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
263 + socket.tag = { first: true, connType: 2, clientCert: null, accumulator: '', activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
264 } else {
229 - socket.tag = { first: true, clientCert: socket.getPeerCertificate(true), accumulator: '', activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
265 + socket.tag = { first: true, connType: 2, clientCert: socket.getPeerCertificate(true), accumulator: '', activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
266 }
267 socket.setEncoding('binary');
268 parent.debug('mps', "New CIRA connection");
@@ -235,6 +271,19 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
271 socket.setTimeout(MAX_IDLE);
272 socket.on('timeout', () => { ciraTimeoutCount++; parent.debug('mps', "CIRA timeout, disconnecting."); try { socket.end(); } catch (e) { } });
273
274 + socket.addListener('close', function () {
275 + socketClosedCount++;
276 + parent.debug('mps', 'CIRA connection closed');
277 + try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
278 + obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connType);
279 + });
280 +
281 + socket.addListener('error', function (e) {
282 + socketErrorCount++;
283 + parent.debug('mps', 'CIRA connection error', e);
284 + //console.log("MPS Error: " + socket.remoteAddress);
285 + });
286 +
287 socket.addListener('data', function (data) {
288 if (args.mpsdebug) { var buf = Buffer.from(data, 'binary'); console.log("MPS --> (" + buf.length + "):" + buf.toString('hex')); } // Print out received bytes
289 socket.tag.accumulator += data;
@@ -334,8 +383,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
383
384 // Add the connection to the MPS connection list
385 obj.ciraConnections[socket.tag.nodeid] = socket;
337 - //obj.parent.SetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, 2, 7); // TODO: Right now report power state as "present" (7) until we can poll.
338 - delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime);
386 + delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, socket.tag.connType);
387 }
388 });
389 return;
@@ -365,7 +413,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
413
414 // Add the connection to the MPS connection list
415 obj.ciraConnections[socket.tag.nodeid] = socket;
368 - delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime);
416 + delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, socket.tag.connType);
417 });
418 } else {
419 // This node connected without certificate authentication, use password auth
@@ -382,355 +430,294 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
430 console.log(e);
431 }
432 });
433 + }
434
386 - // Process one APF command
387 - function ProcessCommand(socket) {
388 - var cmd = socket.tag.accumulator.charCodeAt(0);
389 - var len = socket.tag.accumulator.length;
390 - var data = socket.tag.accumulator;
391 - if (len == 0) { return 0; }
392 -
393 - switch (cmd) {
394 - case APFProtocol.KEEPALIVE_REQUEST: {
395 - if (len < 5) return 0;
396 - parent.debug('mpscmd', '--> KEEPALIVE_REQUEST');
397 - SendKeepAliveReply(socket, common.ReadInt(data, 1));
398 - return 5;
399 - }
400 - case APFProtocol.KEEPALIVE_REPLY: {
401 - if (len < 5) return 0;
402 - parent.debug('mpscmd', '--> KEEPALIVE_REPLY');
403 - return 5;
404 - }
405 - case APFProtocol.PROTOCOLVERSION: {
406 - if (len < 93) return 0;
407 - protocolVersionCount++;
408 - socket.tag.MajorVersion = common.ReadInt(data, 1);
409 - socket.tag.MinorVersion = common.ReadInt(data, 5);
410 - socket.tag.SystemId = guidToStr(common.rstr2hex(data.substring(13, 29))).toLowerCase();
411 - parent.debug('mpscmd', '--> PROTOCOLVERSION', socket.tag.MajorVersion, socket.tag.MinorVersion, socket.tag.SystemId);
412 - return 93;
435 + // Process one APF command
436 + function ProcessCommand(socket) {
437 + var cmd = socket.tag.accumulator.charCodeAt(0);
438 + var len = socket.tag.accumulator.length;
439 + var data = socket.tag.accumulator;
440 + if (len == 0) { return 0; }
441 +
442 + switch (cmd) {
443 + case APFProtocol.KEEPALIVE_REQUEST: {
444 + if (len < 5) return 0;
445 + parent.debug('mpscmd', '--> KEEPALIVE_REQUEST');
446 + SendKeepAliveReply(socket, common.ReadInt(data, 1));
447 + return 5;
448 + }
449 + case APFProtocol.KEEPALIVE_REPLY: {
450 + if (len < 5) return 0;
451 + parent.debug('mpscmd', '--> KEEPALIVE_REPLY');
452 + return 5;
453 + }
454 + case APFProtocol.PROTOCOLVERSION: {
455 + if (len < 93) return 0;
456 + protocolVersionCount++;
457 + socket.tag.MajorVersion = common.ReadInt(data, 1);
458 + socket.tag.MinorVersion = common.ReadInt(data, 5);
459 + socket.tag.SystemId = guidToStr(common.rstr2hex(data.substring(13, 29))).toLowerCase();
460 + parent.debug('mpscmd', '--> PROTOCOLVERSION', socket.tag.MajorVersion, socket.tag.MinorVersion, socket.tag.SystemId);
461 + return 93;
462 + }
463 + case APFProtocol.USERAUTH_REQUEST: {
464 + if (len < 13) return 0;
465 + userAuthRequestCount++;
466 + var usernameLen = common.ReadInt(data, 1);
467 + var username = data.substring(5, 5 + usernameLen);
468 + var serviceNameLen = common.ReadInt(data, 5 + usernameLen);
469 + var serviceName = data.substring(9 + usernameLen, 9 + usernameLen + serviceNameLen);
470 + var methodNameLen = common.ReadInt(data, 9 + usernameLen + serviceNameLen);
471 + var methodName = data.substring(13 + usernameLen + serviceNameLen, 13 + usernameLen + serviceNameLen + methodNameLen);
472 + var passwordLen = 0, password = null;
473 + if (methodName == 'password') {
474 + passwordLen = common.ReadInt(data, 14 + usernameLen + serviceNameLen + methodNameLen);
475 + password = data.substring(18 + usernameLen + serviceNameLen + methodNameLen, 18 + usernameLen + serviceNameLen + methodNameLen + passwordLen);
476 }
414 - case APFProtocol.USERAUTH_REQUEST: {
415 - if (len < 13) return 0;
416 - userAuthRequestCount++;
417 - var usernameLen = common.ReadInt(data, 1);
418 - var username = data.substring(5, 5 + usernameLen);
419 - var serviceNameLen = common.ReadInt(data, 5 + usernameLen);
420 - var serviceName = data.substring(9 + usernameLen, 9 + usernameLen + serviceNameLen);
421 - var methodNameLen = common.ReadInt(data, 9 + usernameLen + serviceNameLen);
422 - var methodName = data.substring(13 + usernameLen + serviceNameLen, 13 + usernameLen + serviceNameLen + methodNameLen);
423 - var passwordLen = 0, password = null;
424 - if (methodName == 'password') {
425 - passwordLen = common.ReadInt(data, 14 + usernameLen + serviceNameLen + methodNameLen);
426 - password = data.substring(18 + usernameLen + serviceNameLen + methodNameLen, 18 + usernameLen + serviceNameLen + methodNameLen + passwordLen);
427 - }
428 - //console.log('MPS:USERAUTH_REQUEST user=' + username + ', service=' + serviceName + ', method=' + methodName + ', password=' + password);
429 - parent.debug('mpscmd', '--> USERAUTH_REQUEST user=' + username + ', service=' + serviceName + ', method=' + methodName + ', password=' + password);
430 -
431 - // Check the CIRA password
432 - if ((args.mpspass != null) && (password != args.mpspass)) { incorrectPasswordCount++; parent.debug('mps', 'Incorrect password', username, password); SendUserAuthFail(socket); return -1; }
433 -
434 - // Check the CIRA username, which should be the start of the MeshID.
435 - if (usernameLen != 16) { badUserNameLengthCount++; parent.debug('mps', 'Username length not 16', username, password); SendUserAuthFail(socket); return -1; }
436 - var meshIdStart = '/' + username, mesh = null;
437 - if (obj.parent.webserver.meshes) { for (var i in obj.parent.webserver.meshes) { if (obj.parent.webserver.meshes[i]._id.replace(/\@/g, 'X').replace(/\$/g, 'X').indexOf(meshIdStart) > 0) { mesh = obj.parent.webserver.meshes[i]; break; } } }
438 - if (mesh == null) { meshNotFoundCount++; parent.debug('mps', 'Device group not found', username, password); SendUserAuthFail(socket); return -1; }
439 -
440 - // If this is a agent-less mesh, use the device guid 3 times as ID.
441 - if (mesh.mtype == 1) {
442 - // Intel AMT GUID (socket.tag.SystemId) will be used as NodeID
443 - var systemid = socket.tag.SystemId.split('-').join('');
444 - var nodeid = Buffer.from(systemid + systemid + systemid, 'hex').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
445 - var domain = obj.parent.config.domains[mesh.domain];
446 - socket.tag.domain = domain;
447 - socket.tag.domainid = mesh.domain;
448 - socket.tag.name = '';
449 - socket.tag.nodeid = 'node/' + mesh.domain + '/' + nodeid; // Turn 16bit systemid guid into 48bit nodeid that is base64 encoded
450 - socket.tag.meshid = mesh._id;
451 - socket.tag.connectTime = Date.now();
452 -
453 - obj.db.Get(socket.tag.nodeid, function (err, nodes) {
454 - if ((nodes == null) || (nodes.length !== 1)) {
455 - // Check if we already have too many devices for this domain
456 - if (domain.limits && (typeof domain.limits.maxdevices == 'number')) {
457 - db.isMaxType(domain.limits.maxdevices, 'node', mesh.domain, function (ismax, count) {
458 - if (ismax == true) {
459 - // Too many devices in this domain.
460 - maxDomainDevicesReached++;
461 - console.log('Too many devices on this domain to accept the CIRA connection. meshid: ' + socket.tag.meshid);
462 - socket.end();
463 - } else {
464 - // We are under the limit, create the new device.
465 - // Node is not in the database, add it. Credentials will be empty until added by the user.
466 - var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: mesh.domain, intelamt: { user: '', pass: '', tls: 0, state: 2 } };
467 - obj.db.Set(device);
468 -
469 - // Event the new node
470 - addedDeviceCount++;
471 - var change = 'CIRA added device ' + socket.tag.name + ' to group ' + mesh.name;
472 - obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: parent.webserver.CloneSafeNode(device), msg: change, domain: mesh.domain });
473 -
474 - // Add the connection to the MPS connection list
475 - obj.ciraConnections[socket.tag.nodeid] = socket;
476 - delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime);
477 - SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
478 - }
479 - });
480 - return;
481 - } else {
482 - // Node is not in the database, add it. Credentials will be empty until added by the user.
483 - var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: mesh.domain, intelamt: { user: '', pass: '', tls: 0, state: 2 } };
484 - obj.db.Set(device);
477 + //console.log('MPS:USERAUTH_REQUEST user=' + username + ', service=' + serviceName + ', method=' + methodName + ', password=' + password);
478 + parent.debug('mpscmd', '--> USERAUTH_REQUEST user=' + username + ', service=' + serviceName + ', method=' + methodName + ', password=' + password);
479 +
480 + // Check the CIRA password
481 + if ((args.mpspass != null) && (password != args.mpspass)) { incorrectPasswordCount++; parent.debug('mps', 'Incorrect password', username, password); SendUserAuthFail(socket); return -1; }
482 +
483 + // Check the CIRA username, which should be the start of the MeshID.
484 + if (usernameLen != 16) { badUserNameLengthCount++; parent.debug('mps', 'Username length not 16', username, password); SendUserAuthFail(socket); return -1; }
485 + var meshIdStart = '/' + username, mesh = null;
486 + if (obj.parent.webserver.meshes) { for (var i in obj.parent.webserver.meshes) { if (obj.parent.webserver.meshes[i]._id.replace(/\@/g, 'X').replace(/\$/g, 'X').indexOf(meshIdStart) > 0) { mesh = obj.parent.webserver.meshes[i]; break; } } }
487 + if (mesh == null) { meshNotFoundCount++; parent.debug('mps', 'Device group not found', username, password); SendUserAuthFail(socket); return -1; }
488 +
489 + // If this is a agent-less mesh, use the device guid 3 times as ID.
490 + if (mesh.mtype == 1) {
491 + // Intel AMT GUID (socket.tag.SystemId) will be used as NodeID
492 + var systemid = socket.tag.SystemId.split('-').join('');
493 + var nodeid = Buffer.from(systemid + systemid + systemid, 'hex').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
494 + var domain = obj.parent.config.domains[mesh.domain];
495 + socket.tag.domain = domain;
496 + socket.tag.domainid = mesh.domain;
497 + socket.tag.name = '';
498 + socket.tag.nodeid = 'node/' + mesh.domain + '/' + nodeid; // Turn 16bit systemid guid into 48bit nodeid that is base64 encoded
499 + socket.tag.meshid = mesh._id;
500 + socket.tag.connectTime = Date.now();
501
486 - // Event the new node
487 - addedDeviceCount++;
488 - var change = 'CIRA added device ' + socket.tag.name + ' to group ' + mesh.name;
489 - obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: parent.webserver.CloneSafeNode(device), msg: change, domain: mesh.domain });
490 - }
502 + obj.db.Get(socket.tag.nodeid, function (err, nodes) {
503 + if ((nodes == null) || (nodes.length !== 1)) {
504 + // Check if we already have too many devices for this domain
505 + if (domain.limits && (typeof domain.limits.maxdevices == 'number')) {
506 + db.isMaxType(domain.limits.maxdevices, 'node', mesh.domain, function (ismax, count) {
507 + if (ismax == true) {
508 + // Too many devices in this domain.
509 + maxDomainDevicesReached++;
510 + console.log('Too many devices on this domain to accept the CIRA connection. meshid: ' + socket.tag.meshid);
511 + socket.end();
512 + } else {
513 + // We are under the limit, create the new device.
514 + // Node is not in the database, add it. Credentials will be empty until added by the user.
515 + var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: mesh.domain, intelamt: { user: '', pass: '', tls: 0, state: 2 } };
516 + obj.db.Set(device);
517 +
518 + // Event the new node
519 + addedDeviceCount++;
520 + var change = 'CIRA added device ' + socket.tag.name + ' to group ' + mesh.name;
521 + obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: parent.webserver.CloneSafeNode(device), msg: change, domain: mesh.domain });
522 +
523 + // Add the connection to the MPS connection list
524 + obj.ciraConnections[socket.tag.nodeid] = socket;
525 + delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, socket.tag.connType);
526 + SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
527 + }
528 + });
529 + return;
530 } else {
492 - // Node is already present
493 - var node = nodes[0];
494 - socket.tag.meshid = node.meshid; // Correct the MeshID if the node has moved.
495 - if ((node.intelamt != null) && (node.intelamt.state == 2)) { socket.tag.host = node.intelamt.host; }
531 + // Node is not in the database, add it. Credentials will be empty until added by the user.
532 + var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: mesh.domain, intelamt: { user: '', pass: '', tls: 0, state: 2 } };
533 + obj.db.Set(device);
534 +
535 + // Event the new node
536 + addedDeviceCount++;
537 + var change = 'CIRA added device ' + socket.tag.name + ' to group ' + mesh.name;
538 + obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: parent.webserver.CloneSafeNode(device), msg: change, domain: mesh.domain });
539 }
540 + } else {
541 + // Node is already present
542 + var node = nodes[0];
543 + socket.tag.meshid = node.meshid; // Correct the MeshID if the node has moved.
544 + if ((node.intelamt != null) && (node.intelamt.state == 2)) { socket.tag.host = node.intelamt.host; }
545 + }
546
498 - // Add the connection to the MPS connection list
499 - obj.ciraConnections[socket.tag.nodeid] = socket;
500 - delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime);
501 - SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
502 - });
503 - } else if (mesh.mtype == 2) { // If this is a agent mesh, search the mesh for this device UUID
504 - // Intel AMT GUID (socket.tag.SystemId) will be used to search the node
505 - obj.db.getAmtUuidNode(socket.tag.SystemId, function (err, nodes) { // TODO: May need to optimize this request with indexes
506 - if ((nodes == null) || (nodes.length === 0) || (obj.parent.webserver.meshes == null)) {
507 - // New CIRA connection for unknown node, disconnect.
508 - unknownNodeCount++;
509 - console.log('CIRA connection for unknown node. groupid: ' + mesh._id + ', uuid: ' + socket.tag.SystemId);
510 - socket.end();
511 - return;
512 - }
547 + // Add the connection to the MPS connection list
548 + obj.ciraConnections[socket.tag.nodeid] = socket;
549 + delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, socket.tag.connType);
550 + SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
551 + });
552 + } else if (mesh.mtype == 2) { // If this is a agent mesh, search the mesh for this device UUID
553 + // Intel AMT GUID (socket.tag.SystemId) will be used to search the node
554 + obj.db.getAmtUuidNode(socket.tag.SystemId, function (err, nodes) { // TODO: May need to optimize this request with indexes
555 + if ((nodes == null) || (nodes.length === 0) || (obj.parent.webserver.meshes == null)) {
556 + // New CIRA connection for unknown node, disconnect.
557 + unknownNodeCount++;
558 + console.log('CIRA connection for unknown node. groupid: ' + mesh._id + ', uuid: ' + socket.tag.SystemId);
559 + socket.end();
560 + return;
561 + }
562
514 - // Looking at nodes that match this UUID, select one in the same domain and mesh type.
515 - var node = null;
516 - for (var i in nodes) {
517 - if (mesh.domain == nodes[i].domain) {
518 - var nodemesh = obj.parent.webserver.meshes[nodes[i].meshid];
519 - if ((nodemesh != null) && (nodemesh.mtype == 2)) { node = nodes[i]; }
520 - }
563 + // Looking at nodes that match this UUID, select one in the same domain and mesh type.
564 + var node = null;
565 + for (var i in nodes) {
566 + if (mesh.domain == nodes[i].domain) {
567 + var nodemesh = obj.parent.webserver.meshes[nodes[i].meshid];
568 + if ((nodemesh != null) && (nodemesh.mtype == 2)) { node = nodes[i]; }
569 }
570 + }
571
523 - if (node == null) {
524 - // New CIRA connection for unknown node, disconnect.
525 - unknownNodeCount++;
526 - console.log('CIRA connection for unknown node. candidate(s): ' + nodes.length + ', groupid: ' + mesh._id + ', uuid: ' + socket.tag.SystemId);
527 - socket.end();
528 - return;
529 - }
572 + if (node == null) {
573 + // New CIRA connection for unknown node, disconnect.
574 + unknownNodeCount++;
575 + console.log('CIRA connection for unknown node. candidate(s): ' + nodes.length + ', groupid: ' + mesh._id + ', uuid: ' + socket.tag.SystemId);
576 + socket.end();
577 + return;
578 + }
579
531 - // Node is present
532 - if ((node.intelamt != null) && (node.intelamt.state == 2)) { socket.tag.host = node.intelamt.host; }
533 - socket.tag.nodeid = node._id;
534 - socket.tag.meshid = node.meshid; // Correct the MeshID if the node has moved.
535 - socket.tag.connectTime = Date.now();
536 -
537 - // Add the connection to the MPS connection list
538 - obj.ciraConnections[socket.tag.nodeid] = socket;
539 - delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime);
540 - SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
541 - });
542 - } else { // Unknown mesh type
543 - // New CIRA connection for unknown node, disconnect.
544 - unknownMeshIdCount++;
545 - console.log('CIRA connection to a unknown group type. groupid: ' + socket.tag.meshid);
546 - socket.end();
547 - return;
548 - }
549 - return 18 + usernameLen + serviceNameLen + methodNameLen + passwordLen;
580 + // Node is present
581 + if ((node.intelamt != null) && (node.intelamt.state == 2)) { socket.tag.host = node.intelamt.host; }
582 + socket.tag.nodeid = node._id;
583 + socket.tag.meshid = node.meshid; // Correct the MeshID if the node has moved.
584 + socket.tag.connectTime = Date.now();
585 +
586 + // Add the connection to the MPS connection list
587 + obj.ciraConnections[socket.tag.nodeid] = socket;
588 + delayedSetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, socket.tag.connType);
589 + SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
590 + });
591 + } else { // Unknown mesh type
592 + // New CIRA connection for unknown node, disconnect.
593 + unknownMeshIdCount++;
594 + console.log('CIRA connection to a unknown group type. groupid: ' + socket.tag.meshid);
595 + socket.end();
596 + return;
597 }
551 - case APFProtocol.SERVICE_REQUEST: {
552 - if (len < 5) return 0;
553 - var xserviceNameLen = common.ReadInt(data, 1);
554 - if (len < 5 + xserviceNameLen) return 0;
555 - var xserviceName = data.substring(5, 5 + xserviceNameLen);
556 - parent.debug('mpscmd', '--> SERVICE_REQUEST', xserviceName);
557 - if (xserviceName == "pfwd@amt.intel.com") { SendServiceAccept(socket, "pfwd@amt.intel.com"); }
558 - if (xserviceName == "auth@amt.intel.com") { SendServiceAccept(socket, "auth@amt.intel.com"); }
559 - return 5 + xserviceNameLen;
598 + return 18 + usernameLen + serviceNameLen + methodNameLen + passwordLen;
599 + }
600 + case APFProtocol.SERVICE_REQUEST: {
601 + if (len < 5) return 0;
602 + var xserviceNameLen = common.ReadInt(data, 1);
603 + if (len < 5 + xserviceNameLen) return 0;
604 + var xserviceName = data.substring(5, 5 + xserviceNameLen);
605 + parent.debug('mpscmd', '--> SERVICE_REQUEST', xserviceName);
606 + if (xserviceName == "pfwd@amt.intel.com") { SendServiceAccept(socket, "pfwd@amt.intel.com"); }
607 + if (xserviceName == "auth@amt.intel.com") { SendServiceAccept(socket, "auth@amt.intel.com"); }
608 + return 5 + xserviceNameLen;
609 + }
610 + case APFProtocol.GLOBAL_REQUEST: {
611 + if (len < 14) return 0;
612 + var requestLen = common.ReadInt(data, 1);
613 + if (len < 14 + requestLen) return 0;
614 + var request = data.substring(5, 5 + requestLen);
615 + //var wantResponse = data.charCodeAt(5 + requestLen);
616 +
617 + if (request == 'tcpip-forward') {
618 + var addrLen = common.ReadInt(data, 6 + requestLen);
619 + if (len < 14 + requestLen + addrLen) return 0;
620 + var addr = data.substring(10 + requestLen, 10 + requestLen + addrLen);
621 + var port = common.ReadInt(data, 10 + requestLen + addrLen);
622 + parent.debug('mpscmd', '--> GLOBAL_REQUEST', request, addr + ':' + port);
623 + ChangeHostname(socket, addr, socket.tag.SystemId);
624 + if (socket.tag.boundPorts.indexOf(port) == -1) { socket.tag.boundPorts.push(port); }
625 + SendTcpForwardSuccessReply(socket, port);
626 + return 14 + requestLen + addrLen;
627 }
561 - case APFProtocol.GLOBAL_REQUEST: {
562 - if (len < 14) return 0;
563 - var requestLen = common.ReadInt(data, 1);
564 - if (len < 14 + requestLen) return 0;
565 - var request = data.substring(5, 5 + requestLen);
566 - //var wantResponse = data.charCodeAt(5 + requestLen);
567 -
568 - if (request == 'tcpip-forward') {
569 - var addrLen = common.ReadInt(data, 6 + requestLen);
570 - if (len < 14 + requestLen + addrLen) return 0;
571 - var addr = data.substring(10 + requestLen, 10 + requestLen + addrLen);
572 - var port = common.ReadInt(data, 10 + requestLen + addrLen);
573 - parent.debug('mpscmd', '--> GLOBAL_REQUEST', request, addr + ':' + port);
574 - ChangeHostname(socket, addr, socket.tag.SystemId);
575 - if (socket.tag.boundPorts.indexOf(port) == -1) { socket.tag.boundPorts.push(port); }
576 - SendTcpForwardSuccessReply(socket, port);
577 - return 14 + requestLen + addrLen;
578 - }
579 -
580 - if (request == 'cancel-tcpip-forward') {
581 - var addrLen = common.ReadInt(data, 6 + requestLen);
582 - if (len < 14 + requestLen + addrLen) return 0;
583 - var addr = data.substring(10 + requestLen, 10 + requestLen + addrLen);
584 - var port = common.ReadInt(data, 10 + requestLen + addrLen);
585 - parent.debug('mpscmd', '--> GLOBAL_REQUEST', request, addr + ':' + port);
586 - var portindex = socket.tag.boundPorts.indexOf(port);
587 - if (portindex >= 0) { socket.tag.boundPorts.splice(portindex, 1); }
588 - SendTcpForwardCancelReply(socket);
589 - return 14 + requestLen + addrLen;
590 - }
591 -
592 - if (request == 'udp-send-to@amt.intel.com') {
593 - var addrLen = common.ReadInt(data, 6 + requestLen);
594 - if (len < 26 + requestLen + addrLen) return 0;
595 - var addr = data.substring(10 + requestLen, 10 + requestLen + addrLen);
596 - var port = common.ReadInt(data, 10 + requestLen + addrLen);
597 - var oaddrLen = common.ReadInt(data, 14 + requestLen + addrLen);
598 - if (len < 26 + requestLen + addrLen + oaddrLen) return 0;
599 - var oaddr = data.substring(18 + requestLen, 18 + requestLen + addrLen);
600 - var oport = common.ReadInt(data, 18 + requestLen + addrLen + oaddrLen);
601 - var datalen = common.ReadInt(data, 22 + requestLen + addrLen + oaddrLen);
602 - if (len < 26 + requestLen + addrLen + oaddrLen + datalen) return 0;
603 - parent.debug('mpscmd', '--> GLOBAL_REQUEST', request, addr + ':' + port, oaddr + ':' + oport, datalen);
604 - // TODO
605 - return 26 + requestLen + addrLen + oaddrLen + datalen;
606 - }
628
608 - return 6 + requestLen;
629 + if (request == 'cancel-tcpip-forward') {
630 + var addrLen = common.ReadInt(data, 6 + requestLen);
631 + if (len < 14 + requestLen + addrLen) return 0;
632 + var addr = data.substring(10 + requestLen, 10 + requestLen + addrLen);
633 + var port = common.ReadInt(data, 10 + requestLen + addrLen);
634 + parent.debug('mpscmd', '--> GLOBAL_REQUEST', request, addr + ':' + port);
635 + var portindex = socket.tag.boundPorts.indexOf(port);
636 + if (portindex >= 0) { socket.tag.boundPorts.splice(portindex, 1); }
637 + SendTcpForwardCancelReply(socket);
638 + return 14 + requestLen + addrLen;
639 }
610 - case APFProtocol.CHANNEL_OPEN: {
611 - if (len < 33) return 0;
612 - var ChannelTypeLength = common.ReadInt(data, 1);
613 - if (len < (33 + ChannelTypeLength)) return 0;
614 -
615 - // Decode channel identifiers and window size
616 - var ChannelType = data.substring(5, 5 + ChannelTypeLength);
617 - var SenderChannel = common.ReadInt(data, 5 + ChannelTypeLength);
618 - var WindowSize = common.ReadInt(data, 9 + ChannelTypeLength);
619 -
620 - // Decode the target
621 - var TargetLen = common.ReadInt(data, 17 + ChannelTypeLength);
622 - if (len < (33 + ChannelTypeLength + TargetLen)) return 0;
623 - var Target = data.substring(21 + ChannelTypeLength, 21 + ChannelTypeLength + TargetLen);
624 - var TargetPort = common.ReadInt(data, 21 + ChannelTypeLength + TargetLen);
625 -
626 - // Decode the source
627 - var SourceLen = common.ReadInt(data, 25 + ChannelTypeLength + TargetLen);
628 - if (len < (33 + ChannelTypeLength + TargetLen + SourceLen)) return 0;
629 - var Source = data.substring(29 + ChannelTypeLength + TargetLen, 29 + ChannelTypeLength + TargetLen + SourceLen);
630 - var SourcePort = common.ReadInt(data, 29 + ChannelTypeLength + TargetLen + SourceLen);
631 -
632 - channelOpenCount++;
633 - parent.debug('mpscmd', '--> CHANNEL_OPEN', ChannelType, SenderChannel, WindowSize, Target + ':' + TargetPort, Source + ':' + SourcePort);
634 -
635 - // Check if we understand this channel type
636 - //if (ChannelType.toLowerCase() == "direct-tcpip")
637 - {
638 - // We don't understand this channel type, send an error back
639 - SendChannelOpenFailure(socket, SenderChannel, APFChannelOpenFailureReasonCode.UnknownChannelType);
640 - return 33 + ChannelTypeLength + TargetLen + SourceLen;
641 - }
640
643 - /*
644 - // This is a correct connection. Lets get it setup
645 - var MeshAmtEventEndpoint = { ServerChannel: GetNextBindId(), AmtChannel: SenderChannel, MaxWindowSize: 2048, CurrentWindowSize:2048, SendWindow: WindowSize, InfoHeader: "Target: " + Target + ":" + TargetPort + ", Source: " + Source + ":" + SourcePort};
646 - // TODO: Connect this socket for a WSMAN event
647 - SendChannelOpenConfirmation(socket, SenderChannel, MeshAmtEventEndpoint.ServerChannel, MeshAmtEventEndpoint.MaxWindowSize);
648 - */
641 + if (request == 'udp-send-to@amt.intel.com') {
642 + var addrLen = common.ReadInt(data, 6 + requestLen);
643 + if (len < 26 + requestLen + addrLen) return 0;
644 + var addr = data.substring(10 + requestLen, 10 + requestLen + addrLen);
645 + var port = common.ReadInt(data, 10 + requestLen + addrLen);
646 + var oaddrLen = common.ReadInt(data, 14 + requestLen + addrLen);
647 + if (len < 26 + requestLen + addrLen + oaddrLen) return 0;
648 + var oaddr = data.substring(18 + requestLen, 18 + requestLen + addrLen);
649 + var oport = common.ReadInt(data, 18 + requestLen + addrLen + oaddrLen);
650 + var datalen = common.ReadInt(data, 22 + requestLen + addrLen + oaddrLen);
651 + if (len < 26 + requestLen + addrLen + oaddrLen + datalen) return 0;
652 + parent.debug('mpscmd', '--> GLOBAL_REQUEST', request, addr + ':' + port, oaddr + ':' + oport, datalen);
653 + // TODO
654 + return 26 + requestLen + addrLen + oaddrLen + datalen;
655 + }
656
657 + return 6 + requestLen;
658 + }
659 + case APFProtocol.CHANNEL_OPEN: {
660 + if (len < 33) return 0;
661 + var ChannelTypeLength = common.ReadInt(data, 1);
662 + if (len < (33 + ChannelTypeLength)) return 0;
663 +
664 + // Decode channel identifiers and window size
665 + var ChannelType = data.substring(5, 5 + ChannelTypeLength);
666 + var SenderChannel = common.ReadInt(data, 5 + ChannelTypeLength);
667 + var WindowSize = common.ReadInt(data, 9 + ChannelTypeLength);
668 +
669 + // Decode the target
670 + var TargetLen = common.ReadInt(data, 17 + ChannelTypeLength);
671 + if (len < (33 + ChannelTypeLength + TargetLen)) return 0;
672 + var Target = data.substring(21 + ChannelTypeLength, 21 + ChannelTypeLength + TargetLen);
673 + var TargetPort = common.ReadInt(data, 21 + ChannelTypeLength + TargetLen);
674 +
675 + // Decode the source
676 + var SourceLen = common.ReadInt(data, 25 + ChannelTypeLength + TargetLen);
677 + if (len < (33 + ChannelTypeLength + TargetLen + SourceLen)) return 0;
678 + var Source = data.substring(29 + ChannelTypeLength + TargetLen, 29 + ChannelTypeLength + TargetLen + SourceLen);
679 + var SourcePort = common.ReadInt(data, 29 + ChannelTypeLength + TargetLen + SourceLen);
680 +
681 + channelOpenCount++;
682 + parent.debug('mpscmd', '--> CHANNEL_OPEN', ChannelType, SenderChannel, WindowSize, Target + ':' + TargetPort, Source + ':' + SourcePort);
683 +
684 + // Check if we understand this channel type
685 + //if (ChannelType.toLowerCase() == "direct-tcpip")
686 + {
687 + // We don't understand this channel type, send an error back
688 + SendChannelOpenFailure(socket, SenderChannel, APFChannelOpenFailureReasonCode.UnknownChannelType);
689 return 33 + ChannelTypeLength + TargetLen + SourceLen;
690 }
652 - case APFProtocol.CHANNEL_OPEN_CONFIRMATION:
653 - {
654 - if (len < 17) return 0;
655 - var RecipientChannel = common.ReadInt(data, 1);
656 - var SenderChannel = common.ReadInt(data, 5);
657 - var WindowSize = common.ReadInt(data, 9);
658 - socket.tag.activetunnels++;
659 - var cirachannel = socket.tag.channels[RecipientChannel];
660 - if (cirachannel == null) { /*console.log("MPS Error in CHANNEL_OPEN_CONFIRMATION: Unable to find channelid " + RecipientChannel);*/ return 17; }
661 - cirachannel.amtchannelid = SenderChannel;
662 - cirachannel.sendcredits = cirachannel.amtCiraWindow = WindowSize;
663 - channelOpenConfirmCount++;
664 - parent.debug('mpscmd', '--> CHANNEL_OPEN_CONFIRMATION', RecipientChannel, SenderChannel, WindowSize);
665 - if (cirachannel.closing == 1) {
666 - // Close this channel
667 - SendChannelClose(cirachannel.socket, cirachannel.amtchannelid);
668 - } else {
669 - cirachannel.state = 2;
670 - // Send any pending data
671 - if (cirachannel.sendBuffer != null) {
672 - if (cirachannel.sendBuffer.length <= cirachannel.sendcredits) {
673 - // Send the entire pending buffer
674 - SendChannelData(cirachannel.socket, cirachannel.amtchannelid, cirachannel.sendBuffer);
675 - cirachannel.sendcredits -= cirachannel.sendBuffer.length;
676 - delete cirachannel.sendBuffer;
677 - if (cirachannel.onSendOk) { cirachannel.onSendOk(cirachannel); }
678 - } else {
679 - // Send a part of the pending buffer
680 - SendChannelData(cirachannel.socket, cirachannel.amtchannelid, cirachannel.sendBuffer.substring(0, cirachannel.sendcredits));
681 - cirachannel.sendBuffer = cirachannel.sendBuffer.substring(cirachannel.sendcredits);
682 - cirachannel.sendcredits = 0;
683 - }
684 - }
685 - // Indicate the channel is open
686 - if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
687 - }
688 - return 17;
689 - }
690 - case APFProtocol.CHANNEL_OPEN_FAILURE:
691 - {
692 - if (len < 17) return 0;
693 - var RecipientChannel = common.ReadInt(data, 1);
694 - var ReasonCode = common.ReadInt(data, 5);
695 - channelOpenFailCount++;
696 - parent.debug('mpscmd', '--> CHANNEL_OPEN_FAILURE', RecipientChannel, ReasonCode);
697 - var cirachannel = socket.tag.channels[RecipientChannel];
698 - if (cirachannel == null) { console.log("MPS Error in CHANNEL_OPEN_FAILURE: Unable to find channelid " + RecipientChannel); return 17; }
699 - if (cirachannel.state > 0) {
700 - cirachannel.state = 0;
701 - if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
702 - delete socket.tag.channels[RecipientChannel];
703 - }
704 - return 17;
705 - }
706 - case APFProtocol.CHANNEL_CLOSE:
707 - {
708 - if (len < 5) return 0;
709 - var RecipientChannel = common.ReadInt(data, 1);
710 - channelCloseCount++;
711 - parent.debug('mpscmd', '--> CHANNEL_CLOSE', RecipientChannel);
712 - var cirachannel = socket.tag.channels[RecipientChannel];
713 - if (cirachannel == null) { console.log("MPS Error in CHANNEL_CLOSE: Unable to find channelid " + RecipientChannel); return 5; }
714 - socket.tag.activetunnels--;
715 - if (cirachannel.state > 0) {
716 - cirachannel.state = 0;
717 - if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
718 - SendChannelClose(cirachannel.socket, cirachannel.amtchannelid);
719 - delete socket.tag.channels[RecipientChannel];
720 - }
721 - return 5;
722 - }
723 - case APFProtocol.CHANNEL_WINDOW_ADJUST:
724 - {
725 - if (len < 9) return 0;
726 - var RecipientChannel = common.ReadInt(data, 1);
727 - var ByteToAdd = common.ReadInt(data, 5);
728 - var cirachannel = socket.tag.channels[RecipientChannel];
729 - if (cirachannel == null) { console.log("MPS Error in CHANNEL_WINDOW_ADJUST: Unable to find channelid " + RecipientChannel); return 9; }
730 - cirachannel.sendcredits += ByteToAdd;
731 - parent.debug('mpscmd', '--> CHANNEL_WINDOW_ADJUST', RecipientChannel, ByteToAdd, cirachannel.sendcredits);
732 - if (cirachannel.state == 2 && cirachannel.sendBuffer != null) {
733 - // Compute how much data we can send
691 +
692 + /*
693 + // This is a correct connection. Lets get it setup
694 + var MeshAmtEventEndpoint = { ServerChannel: GetNextBindId(), AmtChannel: SenderChannel, MaxWindowSize: 2048, CurrentWindowSize:2048, SendWindow: WindowSize, InfoHeader: "Target: " + Target + ":" + TargetPort + ", Source: " + Source + ":" + SourcePort};
695 + // TODO: Connect this socket for a WSMAN event
696 + SendChannelOpenConfirmation(socket, SenderChannel, MeshAmtEventEndpoint.ServerChannel, MeshAmtEventEndpoint.MaxWindowSize);
697 + */
698 +
699 + return 33 + ChannelTypeLength + TargetLen + SourceLen;
700 + }
701 + case APFProtocol.CHANNEL_OPEN_CONFIRMATION:
702 + {
703 + if (len < 17) return 0;
704 + var RecipientChannel = common.ReadInt(data, 1);
705 + var SenderChannel = common.ReadInt(data, 5);
706 + var WindowSize = common.ReadInt(data, 9);
707 + socket.tag.activetunnels++;
708 + var cirachannel = socket.tag.channels[RecipientChannel];
709 + if (cirachannel == null) { /*console.log("MPS Error in CHANNEL_OPEN_CONFIRMATION: Unable to find channelid " + RecipientChannel);*/ return 17; }
710 + cirachannel.amtchannelid = SenderChannel;
711 + cirachannel.sendcredits = cirachannel.amtCiraWindow = WindowSize;
712 + channelOpenConfirmCount++;
713 + parent.debug('mpscmd', '--> CHANNEL_OPEN_CONFIRMATION', RecipientChannel, SenderChannel, WindowSize);
714 + if (cirachannel.closing == 1) {
715 + // Close this channel
716 + SendChannelClose(cirachannel.socket, cirachannel.amtchannelid);
717 + } else {
718 + cirachannel.state = 2;
719 + // Send any pending data
720 + if (cirachannel.sendBuffer != null) {
721 if (cirachannel.sendBuffer.length <= cirachannel.sendcredits) {
722 // Send the entire pending buffer
723 SendChannelData(cirachannel.socket, cirachannel.amtchannelid, cirachannel.sendBuffer);
@@ -744,63 +731,110 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
731 cirachannel.sendcredits = 0;
732 }
733 }
747 - return 9;
734 + // Indicate the channel is open
735 + if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
736 }
749 - case APFProtocol.CHANNEL_DATA:
750 - {
751 - if (len < 9) return 0;
752 - var RecipientChannel = common.ReadInt(data, 1);
753 - var LengthOfData = common.ReadInt(data, 5);
754 - if (len < (9 + LengthOfData)) return 0;
755 - parent.debug('mpscmddata', '--> CHANNEL_DATA', RecipientChannel, LengthOfData);
756 - var cirachannel = socket.tag.channels[RecipientChannel];
757 - if (cirachannel == null) { console.log("MPS Error in CHANNEL_DATA: Unable to find channelid " + RecipientChannel); return 9 + LengthOfData; }
758 - cirachannel.amtpendingcredits += LengthOfData;
759 - if (cirachannel.onData) cirachannel.onData(cirachannel, data.substring(9, 9 + LengthOfData));
760 - if (cirachannel.amtpendingcredits > (cirachannel.ciraWindow / 2)) {
761 - SendChannelWindowAdjust(cirachannel.socket, cirachannel.amtchannelid, cirachannel.amtpendingcredits); // Adjust the buffer window
762 - cirachannel.amtpendingcredits = 0;
763 - }
764 - return 9 + LengthOfData;
737 + return 17;
738 + }
739 + case APFProtocol.CHANNEL_OPEN_FAILURE:
740 + {
741 + if (len < 17) return 0;
742 + var RecipientChannel = common.ReadInt(data, 1);
743 + var ReasonCode = common.ReadInt(data, 5);
744 + channelOpenFailCount++;
745 + parent.debug('mpscmd', '--> CHANNEL_OPEN_FAILURE', RecipientChannel, ReasonCode);
746 + var cirachannel = socket.tag.channels[RecipientChannel];
747 + if (cirachannel == null) { console.log("MPS Error in CHANNEL_OPEN_FAILURE: Unable to find channelid " + RecipientChannel); return 17; }
748 + if (cirachannel.state > 0) {
749 + cirachannel.state = 0;
750 + if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
751 + delete socket.tag.channels[RecipientChannel];
752 }
766 - case APFProtocol.DISCONNECT:
767 - {
768 - if (len < 7) return 0;
769 - var ReasonCode = common.ReadInt(data, 1);
770 - disconnectCommandCount++;
771 - parent.debug('mpscmd', '--> DISCONNECT', ReasonCode);
772 - try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
773 - obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
774 - return 7;
753 + return 17;
754 + }
755 + case APFProtocol.CHANNEL_CLOSE:
756 + {
757 + if (len < 5) return 0;
758 + var RecipientChannel = common.ReadInt(data, 1);
759 + channelCloseCount++;
760 + parent.debug('mpscmd', '--> CHANNEL_CLOSE', RecipientChannel);
761 + var cirachannel = socket.tag.channels[RecipientChannel];
762 + if (cirachannel == null) { console.log("MPS Error in CHANNEL_CLOSE: Unable to find channelid " + RecipientChannel); return 5; }
763 + socket.tag.activetunnels--;
764 + if (cirachannel.state > 0) {
765 + cirachannel.state = 0;
766 + if (cirachannel.onStateChange) { cirachannel.onStateChange(cirachannel, cirachannel.state); }
767 + SendChannelClose(cirachannel.socket, cirachannel.amtchannelid);
768 + delete socket.tag.channels[RecipientChannel];
769 + }
770 + return 5;
771 + }
772 + case APFProtocol.CHANNEL_WINDOW_ADJUST:
773 + {
774 + if (len < 9) return 0;
775 + var RecipientChannel = common.ReadInt(data, 1);
776 + var ByteToAdd = common.ReadInt(data, 5);
777 + var cirachannel = socket.tag.channels[RecipientChannel];
778 + if (cirachannel == null) { console.log("MPS Error in CHANNEL_WINDOW_ADJUST: Unable to find channelid " + RecipientChannel); return 9; }
779 + cirachannel.sendcredits += ByteToAdd;
780 + parent.debug('mpscmd', '--> CHANNEL_WINDOW_ADJUST', RecipientChannel, ByteToAdd, cirachannel.sendcredits);
781 + if (cirachannel.state == 2 && cirachannel.sendBuffer != null) {
782 + // Compute how much data we can send
783 + if (cirachannel.sendBuffer.length <= cirachannel.sendcredits) {
784 + // Send the entire pending buffer
785 + SendChannelData(cirachannel.socket, cirachannel.amtchannelid, cirachannel.sendBuffer);
786 + cirachannel.sendcredits -= cirachannel.sendBuffer.length;
787 + delete cirachannel.sendBuffer;
788 + if (cirachannel.onSendOk) { cirachannel.onSendOk(cirachannel); }
789 + } else {
790 + // Send a part of the pending buffer
791 + SendChannelData(cirachannel.socket, cirachannel.amtchannelid, cirachannel.sendBuffer.substring(0, cirachannel.sendcredits));
792 + cirachannel.sendBuffer = cirachannel.sendBuffer.substring(cirachannel.sendcredits);
793 + cirachannel.sendcredits = 0;
794 + }
795 }
776 - default:
777 - {
778 - parent.debug('mpscmd', '--> Unknown CIRA command: ' + cmd);
779 - return -1;
796 + return 9;
797 + }
798 + case APFProtocol.CHANNEL_DATA:
799 + {
800 + if (len < 9) return 0;
801 + var RecipientChannel = common.ReadInt(data, 1);
802 + var LengthOfData = common.ReadInt(data, 5);
803 + if (len < (9 + LengthOfData)) return 0;
804 + parent.debug('mpscmddata', '--> CHANNEL_DATA', RecipientChannel, LengthOfData);
805 + var cirachannel = socket.tag.channels[RecipientChannel];
806 + if (cirachannel == null) { console.log("MPS Error in CHANNEL_DATA: Unable to find channelid " + RecipientChannel); return 9 + LengthOfData; }
807 + cirachannel.amtpendingcredits += LengthOfData;
808 + if (cirachannel.onData) cirachannel.onData(cirachannel, data.substring(9, 9 + LengthOfData));
809 + if (cirachannel.amtpendingcredits > (cirachannel.ciraWindow / 2)) {
810 + SendChannelWindowAdjust(cirachannel.socket, cirachannel.amtchannelid, cirachannel.amtpendingcredits); // Adjust the buffer window
811 + cirachannel.amtpendingcredits = 0;
812 }
781 - }
813 + return 9 + LengthOfData;
814 + }
815 + case APFProtocol.DISCONNECT:
816 + {
817 + if (len < 7) return 0;
818 + var ReasonCode = common.ReadInt(data, 1);
819 + disconnectCommandCount++;
820 + parent.debug('mpscmd', '--> DISCONNECT', ReasonCode);
821 + try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
822 + obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connType);
823 + return 7;
824 + }
825 + default:
826 + {
827 + parent.debug('mpscmd', '--> Unknown CIRA command: ' + cmd);
828 + return -1;
829 + }
830 }
783 -
784 - socket.addListener('close', function () {
785 - socketClosedCount++;
786 - parent.debug('mps', 'CIRA connection closed');
787 - try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
788 - obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
789 - });
790 -
791 - socket.addListener('error', function () {
792 - socketErrorCount++;
793 - parent.debug('mps', 'CIRA connection error');
794 - //console.log("MPS Error: " + socket.remoteAddress);
795 - });
796 -
831 }
832
833 // Disconnect CIRA tunnel
834 obj.close = function (socket) {
835 try { socket.end(); } catch (e) { }
836 try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
803 - obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
837 + obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connType);
838 };
839
840 function SendServiceAccept(socket, service) {
@@ -886,9 +920,9 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
920 // Print out sent bytes
921 var buf = Buffer.from(data, 'binary');
922 console.log('MPS <-- (' + buf.length + '):' + buf.toString('hex'));
889 - socket.write(buf);
923 + if (socket.websocket == 1) { socket.send(buf); } else { socket.write(buf); }
924 } else {
891 - socket.write(Buffer.from(data, 'binary'));
925 + if (socket.websocket == 1) { socket.send(Buffer.from(data, 'binary')); } else { socket.write(Buffer.from(data, 'binary')); }
926 }
927 }
928
webserver.js
+1 -1
@@ -4846,7 +4846,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4846 obj.app.post(url + 'uploadmeshcorefile.ashx', handleUploadMeshCoreFile);
4847 obj.app.get(url + 'userfiles/*', handleDownloadUserFiles);
4848 obj.app.ws(url + 'echo.ashx', handleEchoWebSocket);
4849 - obj.app.ws(url + 'apf.ashx', function (ws, req) { obj.parent.apfserver.onConnection(ws); })
4849 + obj.app.ws(url + 'apf.ashx', function (ws, req) { obj.parent.mpsserver.onWebSocketConnection(ws); })
4850 obj.app.get(url + 'webrelay.ashx', function (req, res) { res.send('Websocket connection expected'); });
4851 obj.app.get(url + 'health.ashx', function (req, res) { res.send('ok'); }); // TODO: Perform more server checking.
4852 obj.app.ws(url + 'webrelay.ashx', function (ws, req) { PerformWSSessionAuth(ws, req, false, handleRelayWebSocket); });