Added Intel AMT tunneling configuration support.

Ylian Saint-Hilaire committed Oct 17, 2020 at 19:23 UTC fd8265313d107bc1bb2251567de62bc9dcd28c12
8 files changed +709 -109
agents/meshcmd.js
+97 -1
@@ -113,7 +113,7 @@ function run(argv) {
113 //console.log('addedModules = ' + JSON.stringify(addedModules));
114 var actionpath = 'meshaction.txt';
115 if (args.actionfile != null) { actionpath = args.actionfile; }
116 - var actions = ['HELP', 'ROUTE', 'MICROLMS', 'AMTSCAN', 'AMTPOWER', 'AMTFEATURES', 'AMTNETWORK', 'AMTLOADWEBAPP', 'AMTLOADSMALLWEBAPP', 'AMTLOADLARGEWEBAPP', 'AMTCLEARWEBAPP', 'AMTSTORAGESTATE', 'AMTINFO', 'AMTINFODEBUG', 'AMTVERSIONS', 'AMTHASHES', 'AMTSAVESTATE', 'AMTSCRIPT', 'AMTUUID', 'AMTCCM', 'AMTACM', 'AMTDEACTIVATE', 'AMTACMDEACTIVATE', 'SMBIOS', 'RAWSMBIOS', 'MESHCOMMANDER', 'AMTAUDITLOG', 'AMTEVENTLOG', 'AMTPRESENCE', 'AMTWIFI', 'AMTWAKE'];
116 + var actions = ['HELP', 'ROUTE', 'MICROLMS', 'AMTCONFIG', 'AMTSCAN', 'AMTPOWER', 'AMTFEATURES', 'AMTNETWORK', 'AMTLOADWEBAPP', 'AMTLOADSMALLWEBAPP', 'AMTLOADLARGEWEBAPP', 'AMTCLEARWEBAPP', 'AMTSTORAGESTATE', 'AMTINFO', 'AMTINFODEBUG', 'AMTVERSIONS', 'AMTHASHES', 'AMTSAVESTATE', 'AMTSCRIPT', 'AMTUUID', 'AMTCCM', 'AMTACM', 'AMTDEACTIVATE', 'AMTACMDEACTIVATE', 'SMBIOS', 'RAWSMBIOS', 'MESHCOMMANDER', 'AMTAUDITLOG', 'AMTEVENTLOG', 'AMTPRESENCE', 'AMTWIFI', 'AMTWAKE'];
117
118 // Load the action file
119 var actionfile = null;
@@ -129,6 +129,7 @@ function run(argv) {
129 if ((typeof args.localport) == 'string') { settings.localport = parseInt(args.localport); }
130 if ((typeof args.remotenodeid) == 'string') { settings.remotenodeid = args.remotenodeid; }
131 if ((typeof args.name) == 'string') { settings.name = args.name; }
132 + if ((typeof args.id) == 'string') { settings.id = args.id; }
133 if ((typeof args.username) == 'string') { settings.username = args.username; }
134 if ((typeof args.password) == 'string') { settings.password = args.password; }
135 if ((typeof args.url) == 'string') { settings.url = args.url; }
@@ -174,6 +175,7 @@ function run(argv) {
175 console.log(' meshcmd [action] [arguments...]\r\n');
176 console.log('Valid MeshCentral actions:');
177 console.log(' Route - Map a local TCP port to a remote computer.');
178 + console.log(' AmtConfig - Setup Intel AMT on this computer.');
179 console.log('\r\nValid local actions:');
180 console.log(' SMBios - Display System Management BIOS tables for this computer.');
181 console.log(' RawSMBios - Display RAW System Management BIOS tables for this computer.');
@@ -245,6 +247,12 @@ function run(argv) {
247 console.log(' --tag [string] Optional string sent to the server during activation.');
248 console.log(' --serverhttpshash [hash] Optional TLS server certificate hash.');
249 console.log(' --profile [string] Optional profile used for server activation.');
250 + } else if (action == 'amtconfig') {
251 + console.log('AmtConfig will attempt to activate and configure Intel AMT on this computer. The command must be run on a computer with Intel AMT, must run as administrator and the Intel management driver must be installed. Example usage:\r\n\r\n meshcmd amtconfig --url [url]');
252 + console.log('\r\nPossible arguments:\r\n');
253 + console.log(' --url [wss://server] The address of the MeshCentral server.');
254 + console.log(' --id [groupid] The device group identifier.');
255 + console.log(' --serverhttpshash [hash] Optional TLS server certificate hash.');
256 } else if (action == 'amtacm') {
257 console.log('AmtACM will attempt to activate Intel AMT on this computer into admin control mode (ACM). The command must be run on a computer with Intel AMT, must run as administrator and the Intel management driver must be installed. Intel AMT must be in "pre-provisioning" state for this command to work. Example usage:\r\n\r\n meshcmd amtacm --url [url]');
258 console.log('\r\nPossible arguments:\r\n');
@@ -643,6 +651,12 @@ function run(argv) {
651 settings.localport = 16992;
652 debug(1, "Settings: " + JSON.stringify(settings));
653 getAmtUuid();
654 + } else if (settings.action == 'amtconfig') {
655 + // Start Intel AMT configuration
656 + if ((settings.url == null) || (typeof settings.url != 'string') || (settings.url == '')) { console.log('No MeshCentral server URL specified, use --url [url].'); exit(1); return; }
657 + if ((settings.id == null) || (typeof settings.id != 'string') || (settings.id == '')) { console.log('No device group identifier specified, use --id [identifier].'); exit(1); return; }
658 + debug(1, "Settings: " + JSON.stringify(settings));
659 + configureAmt();
660 } else if (settings.action == 'amtccm') {
661 // Start activation to CCM
662 if (((settings.password == null) || (typeof settings.password != 'string') || (settings.password == '')) && ((settings.url == null) || (typeof settings.url != 'string') || (settings.url == ''))) { console.log('No or invalid parameters specified, use --password [password] or --url [url].'); exit(1); return; }
@@ -1127,6 +1141,88 @@ function startMeshCommander() {
1141 }
1142
1143
1144 +//
1145 +// Configure Intel AMT
1146 +//
1147 +
1148 +function configureAmt() {
1149 + console.log('Starting Intel AMT configuration...');
1150 + settings.noconsole = true;
1151 +
1152 + // Display Intel AMT version and activation state
1153 + mestate = {};
1154 + var amtMeiModule, amtMei;
1155 + try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { console.log(ex); exit(1); return; }
1156 + amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
1157 + amtMei.getProvisioningState(function (result) { if (result) { mestate.ProvisioningState = result; } });
1158 + amtMei.getVersion(function (val) { mestate.vers = {}; if (val != null) { for (var version in val.Versions) { mestate.vers[val.Versions[version].Description] = val.Versions[version].Version; } } });
1159 + amtMei.getLanInterfaceSettings(0, function (result) { if (result) { mestate.net0 = result; } });
1160 + amtMei.getUuid(function (result) { if ((result != null) && (result.uuid != null)) { mestate.uuid = result.uuid; } });
1161 + amtMei.getControlMode(function (result) { if (result != null) { mestate.controlMode = result.controlMode; } }); // controlMode: 0 = NoActivated, 1 = CCM, 2 = ACM
1162 + amtMei.getDnsSuffix(function (result) {
1163 + if ((mestate.vers == null) || (mestate.vers['AMT'] == null)) { console.log("Unable to get Intel AMT version."); exit(100); return; }
1164 + if (mestate.ProvisioningState == null) { console.log("Unable to read Intel AMT activation state."); exit(100); return; }
1165 + //if ((settings.action != 'amtdiscover') && (mestate.controlMode == 2)) { console.log("Intel AMT already activation in admin control mode."); exit(100); return; }
1166 + if (mestate.uuid == null) { console.log("Unable to get Intel AMT UUID."); exit(100); return; }
1167 + var fqdn = null;
1168 + //if ((mestate.net0 == null) && (meinfo.net0.enabled != 0)) { console.log("No Intel AMT wired interface, can't perform ACM activation."); exit(100); return; }
1169 + if (result) { fqdn = result; } // If Intel AMT has a trusted DNS suffix set, use that one.
1170 + else {
1171 + // Look for the DNS suffix for the Intel AMT Ethernet interface
1172 + var interfaces = require('os').networkInterfaces();
1173 + for (var i in interfaces) {
1174 + for (var j in interfaces[i]) {
1175 + if ((interfaces[i][j].mac == mestate.net0.mac) && (interfaces[i][j].fqdn != null) && (interfaces[i][j].fqdn != '')) { fqdn = interfaces[i][j].fqdn; }
1176 + }
1177 + }
1178 + }
1179 + if (fqdn != null) { settings.fqdn = fqdn; settings.uuid = mestate.uuid; }
1180 + getTrustedHashes(amtMei, function () { startLms(configureAmt2, amtMei); });
1181 + });
1182 +
1183 +}
1184 +
1185 +function configureAmt2() {
1186 + // Connect to MPS and start APF relay
1187 + var apfarg = {
1188 + mpsurl: settings.url,
1189 + mpsuser: settings.id.substring(0, 16),
1190 + mpspass: settings.id.substring(0, 16),
1191 + mpskeepalive: 60000,
1192 + clientname: require('os').hostname(),
1193 + clientaddress: '127.0.0.1',
1194 + clientuuid: mestate.uuid,
1195 + conntype: 2 // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay.
1196 + };
1197 + if ((apfarg.clientuuid == null) || (apfarg.clientuuid.length != 36)) {
1198 + console.log("Unable to get Intel AMT UUID: " + apfarg.clientuuid);
1199 + exit(1); return;
1200 + } else {
1201 + settings.apftunnel = require('apfclient')({ debug: (settings.debuglevel > 0) }, apfarg);
1202 + settings.apftunnel.onJsonControl = configureJsonControl;
1203 + settings.apftunnel.onChannelClosed = function () { exit(0); }
1204 + try {
1205 + settings.apftunnel.connect();
1206 + console.log("Started APF tunnel...");
1207 + } catch (e) {
1208 + console.log(JSON.stringify(e));
1209 + exit(1); return;
1210 + }
1211 + }
1212 +}
1213 +
1214 +function configureJsonControl(data) {
1215 + switch (data.action) {
1216 + case 'console':
1217 + console.log(data.msg);
1218 + break;
1219 + case 'close':
1220 + exit(0);
1221 + break;
1222 + }
1223 +}
1224 +
1225 +
1226 //
1227 // Deactivate Intel AMT CCM
1228 //
agents/meshcore.js
+30 -3
@@ -2563,7 +2563,7 @@ function createMeshCore(agent) {
2563 var response = null;
2564 switch (cmd) {
2565 case 'help': { // Displays available commands
2566 - var fin = '', f = '', availcommands = 'coredump,service,fdsnapshot,fdcount,startupoptions,alert,agentsize,versions,help,info,osinfo,args,print,type,dbkeys,dbget,dbset,dbcompact,eval,parseuri,httpget,nwslist,plugin,wsconnect,wssend,wsclose,notify,ls,ps,kill,amt,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,sendcaps,openurl,amtreset,amtccm,amtacm,amtdeactivate,amtpolicy,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,scanamt,wallpaper,agentmsg';
2566 + var fin = '', f = '', availcommands = 'amtconfig,coredump,service,fdsnapshot,fdcount,startupoptions,alert,agentsize,versions,help,info,osinfo,args,print,type,dbkeys,dbget,dbset,dbcompact,eval,parseuri,httpget,nwslist,plugin,wsconnect,wssend,wsclose,notify,ls,ps,kill,amt,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,sendcaps,openurl,amtreset,amtccm,amtacm,amtdeactivate,amtpolicy,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,scanamt,wallpaper,agentmsg';
2567 if (process.platform == 'win32') { availcommands += ',safemode,wpfhwacceleration,uac'; }
2568 if (process.platform != 'freebsd') { availcommands += ',vm';}
2569 if (require('MeshAgent').maxKvmTileSize != null) { availcommands += ',kvmmode'; }
@@ -3540,6 +3540,29 @@ function createMeshCore(agent) {
3540 if (diag) { diag.close(); diag = null; }
3541 break;
3542 }
3543 + case 'amtconfig': {
3544 + if (meshCoreObj.intelamt == null) { response = "No Intel AMT support delected"; break; }
3545 + if (apftunnel != null) { response = "Intel AMT server tunnel already active"; break; }
3546 + var apfarg = {
3547 + mpsurl: mesh.ServerUrl.replace('agent.ashx', 'apf.ashx'),
3548 + mpsuser: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
3549 + mpspass: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
3550 + mpskeepalive: 60000,
3551 + clientname: require('os').hostname(),
3552 + clientaddress: '127.0.0.1',
3553 + clientuuid: meshCoreObj.intelamt.uuid,
3554 + conntype: 2 // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay, other values for testing.
3555 + };
3556 + if ((apfarg.clientuuid == null) || (apfarg.clientuuid.length != 36)) { response = "Unable to get Intel AMT UUID"; break; }
3557 + apftunnel = require('apfclient')({ debug: false }, apfarg);
3558 + apftunnel.onJsonControl = function (data) {
3559 + if (data.action == 'console') { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: data.msg }); }
3560 + if (data.action == 'close') { try { apftunnel.disconnect(); } catch (e) { } apftunnel = null; }
3561 + }
3562 + apftunnel.onChannelClosed = function () { apftunnel = null; }
3563 + try { apftunnel.connect(); response = "Started Intel AMT configuration"; } catch (ex) { response = JSON.stringify(ex); }
3564 + break;
3565 + }
3566 case 'apf': {
3567 if (meshCoreObj.intelamt !== null) {
3568 if (args['_'].length == 1) {
@@ -3562,8 +3585,12 @@ function createMeshCore(agent) {
3585 if ((apfarg.clientuuid == null) || (apfarg.clientuuid.length != 36)) {
3586 response = "Unable to get Intel AMT UUID: " + apfarg.clientuuid;
3587 } else {
3565 - var tobj = { debug: false };
3566 - apftunnel = require('apfclient')(tobj, apfarg);
3588 + apftunnel = require('apfclient')({ debug: false }, apfarg);
3589 + apftunnel.onJsonControl = function (data) {
3590 + if (data.action == 'console') { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: data.msg }); }
3591 + if (data.action == 'close') { try { apftunnel.disconnect(); } catch (e) { } apftunnel = null; }
3592 + }
3593 + apftunnel.onChannelClosed = function () { apftunnel = null; }
3594 try {
3595 apftunnel.connect();
3596 response = "Started APF tunnel";
agents/modules_meshcmd/apfclient.js new
+450
@@ -0,0 +1,450 @@
1 +/*
2 +Copyright 2018-2020 Intel Corporation
3 +
4 +Licensed under the Apache License, Version 2.0 (the "License");
5 +you may not use this file except in compliance with the License.
6 +You may obtain a copy of the License at
7 +
8 + http://www.apache.org/licenses/LICENSE-2.0
9 +
10 +Unless required by applicable law or agreed to in writing, software
11 +distributed under the License is distributed on an "AS IS" BASIS,
12 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 +See the License for the specific language governing permissions and
14 +limitations under the License.
15 +*/
16 +
17 +/**
18 +* @description APF/CIRA Client for Duktape
19 +* @author Joko Sastriawan & Ylian Saint-Hilaire
20 +* @copyright Intel Corporation 2020
21 +* @license Apache-2.0
22 +* @version v0.0.2
23 +*/
24 +
25 +function CreateAPFClient(parent, args) {
26 + if ((args.clientuuid == null) || (args.clientuuid.length != 36)) return null; // Require a UUID if this exact length
27 +
28 + var obj = {};
29 + obj.parent = parent;
30 + obj.args = args;
31 + obj.http = require('http');
32 + obj.net = require('net');
33 + obj.forwardClient = null;
34 + obj.downlinks = {};
35 + obj.pfwd_idx = 0;
36 + obj.timer = null; // Keep alive timer
37 +
38 + // obj.onChannelClosed
39 + // obj.onJsonControl
40 +
41 + // Function copied from common.js
42 + 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.
43 + function IntToStr(v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); };
44 + function hex2rstr(d) { var r = '', m = ('' + d).match(/../g), t; while (t = m.shift()) { r += String.fromCharCode('0x' + t); } return r; };
45 + function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); }; // Convert decimal to hex
46 + 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
47 + function d2h(d) { return (d / 256 + 1 / 512).toString(16).substring(2, 4); }
48 + function buf2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += d2h(input[i]); } return r; };
49 + function Debug(str) { if (obj.parent.debug) { console.log(str); } }
50 + 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); }
51 + 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; }
52 + function binzerostring(len) { var res = ''; for (var l = 0; l < len; l++) { res += String.fromCharCode(0 & 0xFF); } return res; }
53 +
54 + // CIRA state
55 + var CIRASTATE = {
56 + INITIAL: 0,
57 + PROTOCOL_VERSION_SENT: 1,
58 + AUTH_SERVICE_REQUEST_SENT: 2,
59 + AUTH_REQUEST_SENT: 3,
60 + PFWD_SERVICE_REQUEST_SENT: 4,
61 + GLOBAL_REQUEST_SENT: 5,
62 + FAILED: -1
63 + }
64 + obj.cirastate = CIRASTATE.INITIAL;
65 +
66 + // REDIR state
67 + var REDIR_TYPE = {
68 + REDIR_UNKNOWN: 0,
69 + REDIR_SOL: 1,
70 + REDIR_KVM: 2,
71 + REDIR_IDER: 3
72 + }
73 +
74 + // redirection start command
75 + obj.RedirectStartSol = String.fromCharCode(0x10, 0x00, 0x00, 0x00, 0x53, 0x4F, 0x4C, 0x20);
76 + obj.RedirectStartKvm = String.fromCharCode(0x10, 0x01, 0x00, 0x00, 0x4b, 0x56, 0x4d, 0x52);
77 + obj.RedirectStartIder = String.fromCharCode(0x10, 0x00, 0x00, 0x00, 0x49, 0x44, 0x45, 0x52);
78 +
79 + // Intel AMT forwarded port list for non-TLS mode
80 + //var pfwd_ports = [16992, 623, 16994, 5900];
81 + var pfwd_ports = [ 16992, 16993 ];
82 +
83 + // protocol definitions
84 + var APFProtocol = {
85 + UNKNOWN: 0,
86 + DISCONNECT: 1,
87 + SERVICE_REQUEST: 5,
88 + SERVICE_ACCEPT: 6,
89 + USERAUTH_REQUEST: 50,
90 + USERAUTH_FAILURE: 51,
91 + USERAUTH_SUCCESS: 52,
92 + GLOBAL_REQUEST: 80,
93 + REQUEST_SUCCESS: 81,
94 + REQUEST_FAILURE: 82,
95 + CHANNEL_OPEN: 90,
96 + CHANNEL_OPEN_CONFIRMATION: 91,
97 + CHANNEL_OPEN_FAILURE: 92,
98 + CHANNEL_WINDOW_ADJUST: 93,
99 + CHANNEL_DATA: 94,
100 + CHANNEL_CLOSE: 97,
101 + PROTOCOLVERSION: 192,
102 + KEEPALIVE_REQUEST: 208,
103 + KEEPALIVE_REPLY: 209,
104 + KEEPALIVE_OPTIONS_REQUEST: 210,
105 + KEEPALIVE_OPTIONS_REPLY: 211,
106 + JSON_CONTROL: 250 // This is a Mesh specific command that sends JSON to and from the MPS server.
107 + }
108 +
109 + var APFDisconnectCode = {
110 + HOST_NOT_ALLOWED_TO_CONNECT: 1,
111 + PROTOCOL_ERROR: 2,
112 + KEY_EXCHANGE_FAILED: 3,
113 + RESERVED: 4,
114 + MAC_ERROR: 5,
115 + COMPRESSION_ERROR: 6,
116 + SERVICE_NOT_AVAILABLE: 7,
117 + PROTOCOL_VERSION_NOT_SUPPORTED: 8,
118 + HOST_KEY_NOT_VERIFIABLE: 9,
119 + CONNECTION_LOST: 10,
120 + BY_APPLICATION: 11,
121 + TOO_MANY_CONNECTIONS: 12,
122 + AUTH_CANCELLED_BY_USER: 13,
123 + NO_MORE_AUTH_METHODS_AVAILABLE: 14,
124 + INVALID_CREDENTIALS: 15,
125 + CONNECTION_TIMED_OUT: 16,
126 + BY_POLICY: 17,
127 + TEMPORARILY_UNAVAILABLE: 18
128 + }
129 +
130 + var APFChannelOpenFailCodes = {
131 + ADMINISTRATIVELY_PROHIBITED: 1,
132 + CONNECT_FAILED: 2,
133 + UNKNOWN_CHANNEL_TYPE: 3,
134 + RESOURCE_SHORTAGE: 4,
135 + }
136 +
137 + var APFChannelOpenFailureReasonCode = {
138 + AdministrativelyProhibited: 1,
139 + ConnectFailed: 2,
140 + UnknownChannelType: 3,
141 + ResourceShortage: 4,
142 + }
143 +
144 + obj.onSecureConnect = function onSecureConnect(resp, ws, head) {
145 + Debug("APF Secure WebSocket connected.");
146 + //console.log(JSON.stringify(resp));
147 + obj.forwardClient.tag = { accumulator: [] };
148 + obj.forwardClient.ws = ws;
149 + obj.forwardClient.ws.on('end', function () {
150 + Debug("APF: Connection is closing.");
151 + if (obj.timer != null) { clearInterval(obj.timer); obj.timer = null; }
152 + if (obj.onChannelClosed) { obj.onChannelClosed(obj); }
153 + });
154 +
155 + obj.forwardClient.ws.on('data', function (data) {
156 + obj.forwardClient.tag.accumulator += hex2rstr(buf2hex(data));
157 + try {
158 + var len = 0;
159 + do {
160 + len = ProcessData(obj.forwardClient);
161 + if (len > 0) { obj.forwardClient.tag.accumulator = obj.forwardClient.tag.accumulator.slice(len); }
162 + if (obj.cirastate == CIRASTATE.FAILED) {
163 + Debug("APF: in a failed state, destroying socket.");
164 + obj.forwardClient.ws.end();
165 + }
166 + } while (len > 0);
167 + } catch (ex) { Debug(ex); }
168 + });
169 +
170 + obj.forwardClient.ws.on('error', function (e) {
171 + Debug("APF: Connection error, ending connecting.");
172 + if (obj.timer != null) { clearInterval(obj.timer); obj.timer = null; }
173 + });
174 +
175 + obj.state = CIRASTATE.INITIAL;
176 + if ((typeof obj.args.conntype == 'number') && (obj.args.conntype != 0)) { SendJsonControl(obj.forwardClient.ws, { action: 'connType', value: obj.args.conntype } ); }
177 + SendProtocolVersion(obj.forwardClient.ws, obj.args.clientuuid);
178 + SendServiceRequest(obj.forwardClient.ws, 'auth@amt.intel.com');
179 + }
180 +
181 + function SendJsonControl(socket, o) {
182 + var data = JSON.stringify(o)
183 + socket.write(String.fromCharCode(APFProtocol.JSON_CONTROL) + IntToStr(data.length) + data);
184 + Debug("APF: Send JSON control: " + data);
185 + }
186 +
187 + function SendProtocolVersion(socket, uuid) {
188 + var data = String.fromCharCode(APFProtocol.PROTOCOLVERSION) + IntToStr(1) + IntToStr(0) + IntToStr(0) + hex2rstr(strToGuid(uuid)) + binzerostring(64);
189 + socket.write(data);
190 + Debug("APF: Send protocol version 1 0 " + uuid);
191 + obj.cirastate = CIRASTATE.PROTOCOL_VERSION_SENT;
192 + }
193 +
194 + function SendServiceRequest(socket, service) {
195 + var data = String.fromCharCode(APFProtocol.SERVICE_REQUEST) + IntToStr(service.length) + service;
196 + socket.write(data);
197 + Debug("APF: Send service request " + service);
198 + if (service == 'auth@amt.intel.com') {
199 + obj.cirastate = CIRASTATE.AUTH_SERVICE_REQUEST_SENT;
200 + } else if (service == 'pfwd@amt.intel.com') {
201 + obj.cirastate = CIRASTATE.PFWD_SERVICE_REQUEST_SENT;
202 + }
203 + }
204 +
205 + function SendUserAuthRequest(socket, user, pass) {
206 + var service = "pfwd@amt.intel.com";
207 + var data = String.fromCharCode(APFProtocol.USERAUTH_REQUEST) + IntToStr(user.length) + user + IntToStr(service.length) + service;
208 + //password auth
209 + data += IntToStr(8) + 'password';
210 + data += binzerostring(1) + IntToStr(pass.length) + pass;
211 + socket.write(data);
212 + Debug("APF: Send username password authentication to MPS");
213 + obj.cirastate = CIRASTATE.AUTH_REQUEST_SENT;
214 + }
215 +
216 + function SendGlobalRequestPfwd(socket, amthostname, amtport) {
217 + var tcpipfwd = 'tcpip-forward';
218 + var data = String.fromCharCode(APFProtocol.GLOBAL_REQUEST) + IntToStr(tcpipfwd.length) + tcpipfwd + binzerostring(1, 1);
219 + data += IntToStr(amthostname.length) + amthostname + IntToStr(amtport);
220 + socket.write(data);
221 + Debug("APF: Send tcpip-forward " + amthostname + ":" + amtport);
222 + obj.cirastate = CIRASTATE.GLOBAL_REQUEST_SENT;
223 + }
224 +
225 + function SendKeepAliveRequest(socket) {
226 + socket.write(String.fromCharCode(APFProtocol.KEEPALIVE_REQUEST) + IntToStr(255));
227 + Debug("APF: Send keepalive request");
228 + }
229 +
230 + function SendKeepAliveReply(socket, cookie) {
231 + socket.write(String.fromCharCode(APFProtocol.KEEPALIVE_REPLY) + IntToStr(cookie));
232 + Debug("APF: Send keepalive reply");
233 + }
234 +
235 + function ProcessData(socket) {
236 + var cmd = socket.tag.accumulator.charCodeAt(0);
237 + var len = socket.tag.accumulator.length;
238 + var data = socket.tag.accumulator;
239 + if (len == 0) { return 0; }
240 +
241 + // Respond to MPS according to obj.cirastate
242 + switch (cmd) {
243 + case APFProtocol.SERVICE_ACCEPT: {
244 + var slen = ReadInt(data, 1), service = data.substring(5, 6 + slen);
245 + Debug("APF: Service request to " + service + " accepted.");
246 + if (service == 'auth@amt.intel.com') {
247 + if (obj.cirastate >= CIRASTATE.AUTH_SERVICE_REQUEST_SENT) {
248 + SendUserAuthRequest(socket.ws, obj.args.mpsuser, obj.args.mpspass);
249 + }
250 + } else if (service == 'pfwd@amt.intel.com') {
251 + if (obj.cirastate >= CIRASTATE.PFWD_SERVICE_REQUEST_SENT) {
252 + SendGlobalRequestPfwd(socket.ws, obj.args.clientname, pfwd_ports[obj.pfwd_idx++]);
253 + }
254 + }
255 + return 5 + slen;
256 + }
257 + case APFProtocol.REQUEST_SUCCESS: {
258 + if (len >= 5) {
259 + var port = ReadInt(data, 1);
260 + Debug("APF: Request to port forward " + port + " successful.");
261 + // iterate to pending port forward request
262 + if (obj.pfwd_idx < pfwd_ports.length) {
263 + SendGlobalRequestPfwd(socket.ws, obj.args.clientname, pfwd_ports[obj.pfwd_idx++]);
264 + } else {
265 + // no more port forward, now setup timer to send keep alive
266 + Debug("APF: Start keep alive for every " + obj.args.mpskeepalive + " ms.");
267 + obj.timer = setInterval(function () {
268 + SendKeepAliveRequest(obj.forwardClient.ws);
269 + }, obj.args.mpskeepalive);//
270 + }
271 + return 5;
272 + }
273 + Debug("APF: Request successful.");
274 + return 1;
275 + }
276 + case APFProtocol.USERAUTH_SUCCESS: {
277 + Debug("APF: User Authentication successful");
278 + // Send Pfwd service request
279 + SendServiceRequest(socket.ws, 'pfwd@amt.intel.com');
280 + return 1;
281 + }
282 + case APFProtocol.USERAUTH_FAILURE: {
283 + Debug("APF: User Authentication failed");
284 + obj.cirastate = CIRASTATE.FAILED;
285 + return 14;
286 + }
287 + case APFProtocol.KEEPALIVE_REQUEST: {
288 + Debug("APF: Keep Alive Request with cookie: " + ReadInt(data, 1));
289 + SendKeepAliveReply(socket.ws, ReadInt(data, 1));
290 + return 5;
291 + }
292 + case APFProtocol.KEEPALIVE_REPLY: {
293 + Debug("APF: Keep Alive Reply with cookie: " + ReadInt(data, 1));
294 + return 5;
295 + }
296 + // Channel management
297 + case APFProtocol.CHANNEL_OPEN: {
298 + // Parse CHANNEL OPEN request
299 + var p_res = parseChannelOpen(data);
300 + Debug("APF: CHANNEL_OPEN request: " + JSON.stringify(p_res));
301 + // Check if target port is in pfwd_ports
302 + if (pfwd_ports.indexOf(p_res.target_port) >= 0) {
303 + // Connect socket to that port
304 + var chan = obj.net.createConnection({ host: obj.args.clientaddress, port: p_res.target_port }, function () {
305 + //require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: "CHANNEL_OPEN-open" });
306 + // obj.downlinks[p_res.sender_chan].setEncoding('binary');//assume everything is binary, not interpreting
307 + SendChannelOpenConfirm(socket.ws, p_res);
308 + });
309 +
310 + // Setup flow control
311 + chan.maxInWindow = p_res.window_size; // Oddly, we are using the same window size as the other side.
312 + chan.curInWindow = 0;
313 +
314 + chan.on('data', function (ddata) {
315 + // Relay data to fordwardclient
316 + // TODO: Implement flow control
317 + SendChannelData(socket.ws, p_res.sender_chan, ddata);
318 + });
319 +
320 + chan.on('error', function (e) {
321 + Debug("Downlink connection error: " + e);
322 + });
323 +
324 + chan.on('end', function () {
325 + var chan = obj.downlinks[p_res.sender_chan];
326 + if (chan != null) {
327 + Debug("Socket ends.");
328 + try { SendChannelClose(socket.ws, p_res.sender_chan); } catch (ex) { }
329 + delete obj.downlinks[p_res.sender_chan];
330 + }
331 + });
332 +
333 + obj.downlinks[p_res.sender_chan] = chan;
334 + } else {
335 + // Not a supported port, fail the connection
336 + SendChannelOpenFailure(socket.ws, p_res);
337 + }
338 + return p_res.len;
339 + }
340 + case APFProtocol.CHANNEL_OPEN_CONFIRMATION: {
341 + Debug("APF: CHANNEL_OPEN_CONFIRMATION");
342 + return 17;
343 + }
344 + case APFProtocol.CHANNEL_CLOSE: {
345 + var rcpt_chan = ReadInt(data, 1);
346 + Debug("APF: CHANNEL_CLOSE: " + rcpt_chan);
347 + try { obj.downlinks[rcpt_chan].end(); } catch (ex) { }
348 + return 5;
349 + }
350 + case APFProtocol.CHANNEL_DATA: {
351 + Debug("APF: CHANNEL_DATA: " + JSON.stringify(rstr2hex(data)));
352 + var rcpt_chan = ReadInt(data, 1);
353 + var chan_data_len = ReadInt(data, 5);
354 + var chan_data = data.substring(9, 9 + chan_data_len);
355 + var chan = obj.downlinks[rcpt_chan];
356 + if (chan != null) {
357 + chan.curInWindow += chan_data_len;
358 + try {
359 + chan.write(Buffer.from(chan_data, 'binary'), function () {
360 + Debug("Write completed.");
361 + // If the incoming window is over half used, send an adjust.
362 + if (this.curInWindow > (this.maxInWindow / 2)) { SendChannelWindowAdjust(socket.ws, rcpt_chan, this.curInWindow); this.curInWindow = 0; }
363 + });
364 + } catch (ex) { Debug("Cannot forward data to downlink socket."); }
365 + }
366 + return 9 + chan_data_len;
367 + }
368 + case APFProtocol.CHANNEL_WINDOW_ADJUST: {
369 + Debug("APF: CHANNEL_WINDOW_ADJUST");
370 + return 9;
371 + }
372 + case APFProtocol.JSON_CONTROL: {
373 + Debug("APF: JSON_CONTROL");
374 + var len = ReadInt(data, 1);
375 + if (obj.onJsonControl) { var o = null; try { o = JSON.parse(data.substring(5, 5 + len)); } catch (ex) { } if (o != null) { obj.onJsonControl(o); } }
376 + return 5 + len;
377 + }
378 + default: {
379 + Debug("CMD: " + cmd + " is not implemented.");
380 + obj.cirastate = CIRASTATE.FAILED;
381 + return 0;
382 + }
383 + }
384 + }
385 +
386 + function parseChannelOpen(data) {
387 + var result = { cmd: APFProtocol.CHANNEL_OPEN };
388 + var chan_type_slen = ReadInt(data, 1);
389 + result.chan_type = data.substring(5, 5 + chan_type_slen);
390 + result.sender_chan = ReadInt(data, 5 + chan_type_slen);
391 + result.window_size = ReadInt(data, 9 + chan_type_slen);
392 + var c_len = ReadInt(data, 17 + chan_type_slen);
393 + result.target_address = data.substring(21 + chan_type_slen, 21 + chan_type_slen + c_len);
394 + result.target_port = ReadInt(data, 21 + chan_type_slen + c_len);
395 + var o_len = ReadInt(data, 25 + chan_type_slen + c_len);
396 + result.origin_address = data.substring(29 + chan_type_slen + c_len, 29 + chan_type_slen + c_len + o_len);
397 + result.origin_port = ReadInt(data, 29 + chan_type_slen + c_len + o_len);
398 + result.len = 33 + chan_type_slen + c_len + o_len;
399 + return result;
400 + }
401 +
402 + function SendChannelOpenFailure(socket, chan_data) {
403 + socket.write(String.fromCharCode(APFProtocol.CHANNEL_OPEN_FAILURE) + IntToStr(chan_data.sender_chan) + IntToStr(2) + IntToStr(0) + IntToStr(0));
404 + Debug("APF: Send ChannelOpenFailure");
405 + }
406 +
407 + function SendChannelOpenConfirm(socket, chan_data) {
408 + socket.write(String.fromCharCode(APFProtocol.CHANNEL_OPEN_CONFIRMATION) + IntToStr(chan_data.sender_chan) + IntToStr(chan_data.sender_chan) + IntToStr(chan_data.window_size) + IntToStr(0xFFFFFFFF));
409 + Debug("APF: Send ChannelOpenConfirmation");
410 + }
411 +
412 + function SendChannelWindowAdjust(socket, chan, size) {
413 + socket.write(String.fromCharCode(APFProtocol.CHANNEL_WINDOW_ADJUST) + IntToStr(chan) + IntToStr(size));
414 + Debug("APF: Send ChannelWindowAdjust, channel: " + chan + ", size: " + size);
415 + }
416 +
417 + function SendChannelData(socket, chan, data) {
418 + socket.write(Buffer.concat([Buffer.from(String.fromCharCode(APFProtocol.CHANNEL_DATA) + IntToStr(chan) + IntToStr(data.length), 'binary'), data]));
419 + Debug("APF: Send ChannelData: " + data.toString('hex'));
420 + }
421 +
422 + function SendChannelClose(socket, chan) {
423 + socket.write(String.fromCharCode(APFProtocol.CHANNEL_CLOSE) + IntToStr(chan));
424 + Debug("APF: Send ChannelClose ");
425 + }
426 +
427 + obj.connect = function () {
428 + if (obj.forwardClient != null) {
429 + try { obj.forwardClient.ws.end(); } catch (ex) { Debug(ex); }
430 + //obj.forwardClient = null;
431 + }
432 + obj.cirastate = CIRASTATE.INITIAL;
433 + obj.pfwd_idx = 0;
434 +
435 + //obj.forwardClient = new obj.ws(obj.args.mpsurl, obj.tlsoptions);
436 + //obj.forwardClient.on("open", obj.onSecureConnect);
437 +
438 + var wsoptions = obj.http.parseUri(obj.args.mpsurl);
439 + wsoptions.rejectUnauthorized = 0;
440 + obj.forwardClient = obj.http.request(wsoptions);
441 + obj.forwardClient.upgrade = obj.onSecureConnect;
442 + obj.forwardClient.end(); // end request, trigger completion of HTTP request
443 + }
444 +
445 + obj.disconnect = function () { try { obj.forwardClient.ws.end(); } catch (ex) { Debug(ex); } }
446 +
447 + return obj;
448 +}
449 +
450 +module.exports = CreateAPFClient;
\ No newline at end of file
agents/modules_meshcore/apfclient.js
+52 -67
@@ -35,6 +35,9 @@ function CreateAPFClient(parent, args) {
35 obj.pfwd_idx = 0;
36 obj.timer = null; // Keep alive timer
37
38 + // obj.onChannelClosed
39 + // obj.onJsonControl
40 +
41 // Function copied from common.js
42 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.
43 function IntToStr(v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); };
@@ -139,16 +142,14 @@ function CreateAPFClient(parent, args) {
142 }
143
144 obj.onSecureConnect = function onSecureConnect(resp, ws, head) {
142 - //Debug("APF Secure WebSocket connected.");
145 + Debug("APF Secure WebSocket connected.");
146 //console.log(JSON.stringify(resp));
147 obj.forwardClient.tag = { accumulator: [] };
148 obj.forwardClient.ws = ws;
149 obj.forwardClient.ws.on('end', function () {
147 - //Debug("APF: Connection is closing.");
148 - if (obj.timer != null) {
149 - clearInterval(obj.timer);
150 - obj.timer = null;
151 - }
150 + Debug("APF: Connection is closing.");
151 + if (obj.timer != null) { clearInterval(obj.timer); obj.timer = null; }
152 + if (obj.onChannelClosed) { obj.onChannelClosed(obj); }
153 });
154
155 obj.forwardClient.ws.on('data', function (data) {
@@ -159,21 +160,16 @@ function CreateAPFClient(parent, args) {
160 len = ProcessData(obj.forwardClient);
161 if (len > 0) { obj.forwardClient.tag.accumulator = obj.forwardClient.tag.accumulator.slice(len); }
162 if (obj.cirastate == CIRASTATE.FAILED) {
162 - //Debug("APF: in a failed state, destroying socket.");
163 + Debug("APF: in a failed state, destroying socket.");
164 obj.forwardClient.ws.end();
165 }
166 } while (len > 0);
166 - } catch (e) {
167 - Debug(e);
168 - }
167 + } catch (ex) { Debug(ex); }
168 });
169
170 obj.forwardClient.ws.on('error', function (e) {
172 - //Debug("APF: Connection error, ending connecting.");
173 - if (obj.timer != null) {
174 - clearInterval(obj.timer);
175 - obj.timer = null;
176 - }
171 + Debug("APF: Connection error, ending connecting.");
172 + if (obj.timer != null) { clearInterval(obj.timer); obj.timer = null; }
173 });
174
175 obj.state = CIRASTATE.INITIAL;
@@ -185,20 +181,20 @@ function CreateAPFClient(parent, args) {
181 function SendJsonControl(socket, o) {
182 var data = JSON.stringify(o)
183 socket.write(String.fromCharCode(APFProtocol.JSON_CONTROL) + IntToStr(data.length) + data);
188 - //Debug("APF: Send JSON control: " + data);
184 + Debug("APF: Send JSON control: " + data);
185 }
186
187 function SendProtocolVersion(socket, uuid) {
188 var data = String.fromCharCode(APFProtocol.PROTOCOLVERSION) + IntToStr(1) + IntToStr(0) + IntToStr(0) + hex2rstr(strToGuid(uuid)) + binzerostring(64);
189 socket.write(data);
194 - //Debug("APF: Send protocol version 1 0 " + uuid);
190 + Debug("APF: Send protocol version 1 0 " + uuid);
191 obj.cirastate = CIRASTATE.PROTOCOL_VERSION_SENT;
192 }
193
194 function SendServiceRequest(socket, service) {
195 var data = String.fromCharCode(APFProtocol.SERVICE_REQUEST) + IntToStr(service.length) + service;
196 socket.write(data);
201 - //Debug("APF: Send service request " + service);
197 + Debug("APF: Send service request " + service);
198 if (service == 'auth@amt.intel.com') {
199 obj.cirastate = CIRASTATE.AUTH_SERVICE_REQUEST_SENT;
200 } else if (service == 'pfwd@amt.intel.com') {
@@ -213,7 +209,7 @@ function CreateAPFClient(parent, args) {
209 data += IntToStr(8) + 'password';
210 data += binzerostring(1) + IntToStr(pass.length) + pass;
211 socket.write(data);
216 - //Debug("APF: Send username password authentication to MPS");
212 + Debug("APF: Send username password authentication to MPS");
213 obj.cirastate = CIRASTATE.AUTH_REQUEST_SENT;
214 }
215
@@ -222,18 +218,18 @@ function CreateAPFClient(parent, args) {
218 var data = String.fromCharCode(APFProtocol.GLOBAL_REQUEST) + IntToStr(tcpipfwd.length) + tcpipfwd + binzerostring(1, 1);
219 data += IntToStr(amthostname.length) + amthostname + IntToStr(amtport);
220 socket.write(data);
225 - //Debug("APF: Send tcpip-forward " + amthostname + ":" + amtport);
221 + Debug("APF: Send tcpip-forward " + amthostname + ":" + amtport);
222 obj.cirastate = CIRASTATE.GLOBAL_REQUEST_SENT;
223 }
224
225 function SendKeepAliveRequest(socket) {
226 socket.write(String.fromCharCode(APFProtocol.KEEPALIVE_REQUEST) + IntToStr(255));
231 - //Debug("APF: Send keepalive request");
227 + Debug("APF: Send keepalive request");
228 }
229
230 function SendKeepAliveReply(socket, cookie) {
231 socket.write(String.fromCharCode(APFProtocol.KEEPALIVE_REPLY) + IntToStr(cookie));
236 - //Debug("APF: Send keepalive reply");
232 + Debug("APF: Send keepalive reply");
233 }
234
235 function ProcessData(socket) {
@@ -246,7 +242,7 @@ function CreateAPFClient(parent, args) {
242 switch (cmd) {
243 case APFProtocol.SERVICE_ACCEPT: {
244 var slen = ReadInt(data, 1), service = data.substring(5, 6 + slen);
249 - //Debug("APF: Service request to " + service + " accepted.");
245 + Debug("APF: Service request to " + service + " accepted.");
246 if (service == 'auth@amt.intel.com') {
247 if (obj.cirastate >= CIRASTATE.AUTH_SERVICE_REQUEST_SENT) {
248 SendUserAuthRequest(socket.ws, obj.args.mpsuser, obj.args.mpspass);
@@ -261,47 +257,47 @@ function CreateAPFClient(parent, args) {
257 case APFProtocol.REQUEST_SUCCESS: {
258 if (len >= 5) {
259 var port = ReadInt(data, 1);
264 - //Debug("APF: Request to port forward " + port + " successful.");
260 + Debug("APF: Request to port forward " + port + " successful.");
261 // iterate to pending port forward request
262 if (obj.pfwd_idx < pfwd_ports.length) {
263 SendGlobalRequestPfwd(socket.ws, obj.args.clientname, pfwd_ports[obj.pfwd_idx++]);
264 } else {
265 // no more port forward, now setup timer to send keep alive
270 - //Debug("APF: Start keep alive for every " + obj.args.mpskeepalive + " ms.");
266 + Debug("APF: Start keep alive for every " + obj.args.mpskeepalive + " ms.");
267 obj.timer = setInterval(function () {
268 SendKeepAliveRequest(obj.forwardClient.ws);
269 }, obj.args.mpskeepalive);//
270 }
271 return 5;
272 }
277 - //Debug("APF: Request successful.");
273 + Debug("APF: Request successful.");
274 return 1;
275 }
276 case APFProtocol.USERAUTH_SUCCESS: {
281 - //Debug("APF: User Authentication successful");
277 + Debug("APF: User Authentication successful");
278 // Send Pfwd service request
279 SendServiceRequest(socket.ws, 'pfwd@amt.intel.com');
280 return 1;
281 }
282 case APFProtocol.USERAUTH_FAILURE: {
287 - //Debug("APF: User Authentication failed");
283 + Debug("APF: User Authentication failed");
284 obj.cirastate = CIRASTATE.FAILED;
285 return 14;
286 }
287 case APFProtocol.KEEPALIVE_REQUEST: {
292 - //Debug("APF: Keep Alive Request with cookie: " + ReadInt(data, 1));
288 + Debug("APF: Keep Alive Request with cookie: " + ReadInt(data, 1));
289 SendKeepAliveReply(socket.ws, ReadInt(data, 1));
290 return 5;
291 }
292 case APFProtocol.KEEPALIVE_REPLY: {
297 - //Debug("APF: Keep Alive Reply with cookie: " + ReadInt(data, 1));
293 + Debug("APF: Keep Alive Reply with cookie: " + ReadInt(data, 1));
294 return 5;
295 }
296 // Channel management
297 case APFProtocol.CHANNEL_OPEN: {
298 // Parse CHANNEL OPEN request
299 var p_res = parseChannelOpen(data);
304 - //Debug("APF: CHANNEL_OPEN request: " + JSON.stringify(p_res));
300 + Debug("APF: CHANNEL_OPEN request: " + JSON.stringify(p_res));
301 // Check if target port is in pfwd_ports
302 if (pfwd_ports.indexOf(p_res.target_port) >= 0) {
303 // Connect socket to that port
@@ -322,21 +318,15 @@ function CreateAPFClient(parent, args) {
318 });
319
320 chan.on('error', function (e) {
325 - //Debug("Downlink connection error: " + e);
321 + Debug("Downlink connection error: " + e);
322 });
323
324 chan.on('end', function () {
325 var chan = obj.downlinks[p_res.sender_chan];
326 if (chan != null) {
331 - try {
332 - //Debug("Socket ends.");
333 - SendChannelClose(socket.ws, p_res.sender_chan);
334 - chan.xclosed = 1;
335 - // Add some delay before removing... otherwise race condition
336 - setTimeout(function () { delete obj.downlinks[p_res.sender_chan]; }, 100);
337 - } catch (e) {
338 - //Debug("Downlink connection exception: " + e);
339 - }
327 + Debug("Socket ends.");
328 + try { SendChannelClose(socket.ws, p_res.sender_chan); } catch (ex) { }
329 + delete obj.downlinks[p_res.sender_chan];
330 }
331 });
332
@@ -348,22 +338,17 @@ function CreateAPFClient(parent, args) {
338 return p_res.len;
339 }
340 case APFProtocol.CHANNEL_OPEN_CONFIRMATION: {
351 - //Debug("APF: CHANNEL_OPEN_CONFIRMATION");
341 + Debug("APF: CHANNEL_OPEN_CONFIRMATION");
342 return 17;
343 }
344 case APFProtocol.CHANNEL_CLOSE: {
345 var rcpt_chan = ReadInt(data, 1);
356 - //Debug("APF: CHANNEL_CLOSE: " + rcpt_chan);
357 - var chan = obj.downlinks[rcpt_chan];
358 - if ((chan != null) && (chan.xclosed !== 1)) {
359 - SendChannelClose(socket.ws, rcpt_chan);
360 - try { obj.downlinks[rcpt_chan].end(); } catch (e) { }
361 - delete obj.downlinks[rcpt_chan];
362 - }
346 + Debug("APF: CHANNEL_CLOSE: " + rcpt_chan);
347 + try { obj.downlinks[rcpt_chan].end(); } catch (ex) { }
348 return 5;
349 }
350 case APFProtocol.CHANNEL_DATA: {
366 - //Debug("APF: CHANNEL_DATA: " + JSON.stringify(rstr2hex(data)));
351 + Debug("APF: CHANNEL_DATA: " + JSON.stringify(rstr2hex(data)));
352 var rcpt_chan = ReadInt(data, 1);
353 var chan_data_len = ReadInt(data, 5);
354 var chan_data = data.substring(9, 9 + chan_data_len);
@@ -372,22 +357,26 @@ function CreateAPFClient(parent, args) {
357 chan.curInWindow += chan_data_len;
358 try {
359 chan.write(Buffer.from(chan_data, 'binary'), function () {
375 - //Debug("Write completed.");
360 + Debug("Write completed.");
361 // If the incoming window is over half used, send an adjust.
362 if (this.curInWindow > (this.maxInWindow / 2)) { SendChannelWindowAdjust(socket.ws, rcpt_chan, this.curInWindow); this.curInWindow = 0; }
363 });
379 - } catch (e) {
380 - //Debug("Cannot forward data to downlink socket.");
381 - }
364 + } catch (ex) { Debug("Cannot forward data to downlink socket."); }
365 }
366 return 9 + chan_data_len;
367 }
368 case APFProtocol.CHANNEL_WINDOW_ADJUST: {
386 - //Debug("APF: CHANNEL_WINDOW_ADJUST ");
369 + Debug("APF: CHANNEL_WINDOW_ADJUST");
370 return 9;
371 }
372 + case APFProtocol.JSON_CONTROL: {
373 + Debug("APF: JSON_CONTROL");
374 + var len = ReadInt(data, 1);
375 + if (obj.onJsonControl) { var o = null; try { o = JSON.parse(data.substring(5, 5 + len)); } catch (ex) { } if (o != null) { obj.onJsonControl(o); } }
376 + return 5 + len;
377 + }
378 default: {
390 - //Debug("CMD: " + cmd + " is not implemented.");
379 + Debug("CMD: " + cmd + " is not implemented.");
380 obj.cirastate = CIRASTATE.FAILED;
381 return 0;
382 }
@@ -412,36 +401,32 @@ function CreateAPFClient(parent, args) {
401
402 function SendChannelOpenFailure(socket, chan_data) {
403 socket.write(String.fromCharCode(APFProtocol.CHANNEL_OPEN_FAILURE) + IntToStr(chan_data.sender_chan) + IntToStr(2) + IntToStr(0) + IntToStr(0));
415 - //Debug("APF: Send ChannelOpenFailure");
404 + Debug("APF: Send ChannelOpenFailure");
405 }
406
407 function SendChannelOpenConfirm(socket, chan_data) {
408 socket.write(String.fromCharCode(APFProtocol.CHANNEL_OPEN_CONFIRMATION) + IntToStr(chan_data.sender_chan) + IntToStr(chan_data.sender_chan) + IntToStr(chan_data.window_size) + IntToStr(0xFFFFFFFF));
420 - //Debug("APF: Send ChannelOpenConfirmation");
409 + Debug("APF: Send ChannelOpenConfirmation");
410 }
411
412 function SendChannelWindowAdjust(socket, chan, size) {
413 socket.write(String.fromCharCode(APFProtocol.CHANNEL_WINDOW_ADJUST) + IntToStr(chan) + IntToStr(size));
425 - //Debug("APF: Send ChannelWindowAdjust: " + rstr2hex(data));
414 + Debug("APF: Send ChannelWindowAdjust, channel: " + chan + ", size: " + size);
415 }
416
417 function SendChannelData(socket, chan, data) {
418 socket.write(Buffer.concat([Buffer.from(String.fromCharCode(APFProtocol.CHANNEL_DATA) + IntToStr(chan) + IntToStr(data.length), 'binary'), data]));
430 - //Debug("APF: Send ChannelData: " + rstr2hex(buf));
419 + Debug("APF: Send ChannelData: " + data.toString('hex'));
420 }
421
422 function SendChannelClose(socket, chan) {
423 socket.write(String.fromCharCode(APFProtocol.CHANNEL_CLOSE) + IntToStr(chan));
435 - //Debug("APF: Send ChannelClose ");
424 + Debug("APF: Send ChannelClose ");
425 }
426
427 obj.connect = function () {
428 if (obj.forwardClient != null) {
440 - try {
441 - obj.forwardClient.ws.end();
442 - } catch (e) {
443 - Debug(e);
444 - }
429 + try { obj.forwardClient.ws.end(); } catch (ex) { Debug(ex); }
430 //obj.forwardClient = null;
431 }
432 obj.cirastate = CIRASTATE.INITIAL;
@@ -457,7 +442,7 @@ function CreateAPFClient(parent, args) {
442 obj.forwardClient.end(); // end request, trigger completion of HTTP request
443 }
444
460 - obj.disconnect = function () { try { obj.forwardClient.ws.end(); } catch (e) { Debug(e); } }
445 + obj.disconnect = function () { try { obj.forwardClient.ws.end(); } catch (ex) { Debug(ex); } }
446
447 return obj;
448 }
amt/amt-wsman-comm.js
+2 -4
@@ -240,19 +240,17 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, mpsConn
240 if (state == 2) {
241 // TLSSocket to encapsulate TLS communication, which then tunneled via SerialTunnel an then wrapped through CIRA APF
242 var options = { socket: ser, ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false };
243 - if (obj.tls1only == 1) { tlsoptions.secureProtocol = 'TLSv1_method'; }
243 + if (obj.xtlsMethod == 1) { options.secureProtocol = 'TLSv1_method'; }
244 if (obj.xtlsoptions) {
245 if (obj.xtlsoptions.ca) options.ca = obj.xtlsoptions.ca;
246 if (obj.xtlsoptions.cert) options.cert = obj.xtlsoptions.cert;
247 if (obj.xtlsoptions.key) options.key = obj.xtlsoptions.key;
248 }
249
250 - //obj.socket = new TLSSocket(ser, options);
250 obj.socket = obj.tls.connect(obj.port, obj.host, options, obj.xxOnSocketConnected);
251 obj.socket.setEncoding('binary');
252 obj.socket.setTimeout(6000); // Set socket idle timeout
254 - obj.socket.on('error', function (err) { console.log("CIRA TLS Connection Error ", err); obj.xxOnSocketClosed(); });
255 - //obj.socket.on('error', function (e) { if (e.message && e.message.indexOf('sslv3 alert bad record mac') >= 0) { obj.xtlsMethod = 1 - obj.xtlsMethod; } });
253 + obj.socket.on('error', function (ex) { obj.xtlsMethod = 1 - obj.xtlsMethod; });
254 obj.socket.on('close', obj.xxOnSocketClosed);
255 obj.socket.on('timeout', obj.xxOnSocketTimeout);
256
amtmanager.js
+65 -33
@@ -76,6 +76,9 @@ module.exports.CreateAmtManager = function(parent) {
76 // Remove the device from the list
77 devices.splice(i, 1);
78 if (devices.length == 0) { delete obj.amtDevices[dev.nodeid]; } else { obj.amtDevices[dev.nodeid] = devices; }
79 +
80 + // Notify connection closure if this is a LMS connection
81 + if (dev.connType == 2) { dev.controlMsg({ action: "close" }); }
82 return true;
83 }
84
@@ -103,9 +106,13 @@ module.exports.CreateAmtManager = function(parent) {
106 var devices = obj.amtDevices[nodeid], dev = null;
107 if (devices != null) { for (var i in devices) { if ((devices[i].mpsConnection == connection) || (devices[i].host == connection)) { dev = devices[i]; } } }
108 if (dev != null) return false; // We are already managing this device on this connection
106 - dev = { nodeid: nodeid, connType: connType };
109 + dev = { nodeid: nodeid, connType: connType, domainid: nodeid.split('/')[1] };
110 if (typeof connection == 'string') { dev.host = connection; }
111 if (typeof connection == 'object') { dev.mpsConnection = connection; }
112 + dev.consoleMsg = function deviceConsoleMsg(msg) { if (typeof deviceConsoleMsg.conn == 'object') { deviceConsoleMsg.conn.ControlMsg({ action: 'console', msg: msg }); } }
113 + dev.consoleMsg.conn = connection;
114 + dev.controlMsg = function deviceControlMsg(msg) { if (typeof deviceControlMsg.conn == 'object') { deviceControlMsg.conn.ControlMsg(msg); } }
115 + dev.controlMsg.conn = connection;
116 parent.debug('amt', "Start Management", nodeid, connType);
117 addAmtDevice(dev);
118 fetchIntelAmtInformation(dev);
@@ -192,6 +199,7 @@ module.exports.CreateAmtManager = function(parent) {
199 //if (node.host) { dev.host = node.host.toLowerCase(); }
200 dev.meshid = node.meshid;
201 dev.intelamt = node.intelamt;
202 + dev.consoleMsg("Attempting Intel AMT connection...");
203 attemptInitialContact(dev);
204 });
205 }
@@ -201,7 +209,7 @@ module.exports.CreateAmtManager = function(parent) {
209 parent.debug('amt', "Attempt Initial Contact", dev.name, dev.connType);
210
211 if ((dev.acctry == null) && ((typeof dev.intelamt.user != 'string') || (typeof dev.intelamt.pass != 'string'))) {
204 - if ((obj.amtAdminAccounts[dev.domainid] != null) && (obj.amtAdminAccounts[dev.domainid].length > 0)) { dev.acctry = 0; } else { return; }
212 + if ((obj.amtAdminAccounts[dev.domainid] != null) && (obj.amtAdminAccounts[dev.domainid].length > 0)) { dev.acctry = 0; } else { removeAmtDevice(dev); return; }
213 }
214
215 switch (dev.connType) {
@@ -315,6 +323,7 @@ module.exports.CreateAmtManager = function(parent) {
323 // Check the response
324 if ((status == 200) && (responses['AMT_GeneralSettings'] != null) && (responses['IPS_HostBasedSetupService'] != null) && (responses['IPS_HostBasedSetupService'].response != null) && (responses['IPS_HostBasedSetupService'].response != null) && (stack.wsman.comm.digestRealm == responses['AMT_GeneralSettings'].response.DigestRealm)) {
325 // Everything looks good
326 + dev.consoleMsg(stack.wsman.comm.xtls ? "Intel AMT connected with TLS." : "Intel AMT connected.");
327 dev.state = 1;
328 if (dev.aquired == null) { dev.aquired = {}; }
329 dev.aquired.controlMode = responses['IPS_HostBasedSetupService'].response.CurrentControlMode; // 1 = CCM, 2 = ACM
@@ -330,15 +339,20 @@ module.exports.CreateAmtManager = function(parent) {
339
340 // Perform Intel AMT clock sync
341 attemptSyncClock(dev, function () {
333 - attemptFetchHardwareInventory(dev); // See if we need to get hardware inventory
334 -
335 - if (dev.connType != 2) {
336 - // Start power polling if not connected to LMS
337 - var ppfunc = function powerPoleFunction() { fetchPowerState(powerPoleFunction.dev); }
338 - ppfunc.dev = dev;
339 - dev.polltimer = new setTimeout(ppfunc, 290000); // Poll for power state every 4 minutes 50 seconds.
340 - fetchPowerState(dev);
341 - }
342 + // See if we need to get hardware inventory
343 + attemptFetchHardwareInventory(dev, function () {
344 + dev.consoleMsg('Done.');
345 + if (dev.connType != 2) {
346 + // Start power polling if not connected to LMS
347 + var ppfunc = function powerPoleFunction() { fetchPowerState(powerPoleFunction.dev); }
348 + ppfunc.dev = dev;
349 + dev.polltimer = new setTimeout(ppfunc, 290000); // Poll for power state every 4 minutes 50 seconds.
350 + fetchPowerState(dev);
351 + } else {
352 + // For LMS connections, close now.
353 + dev.controlMsg({ action: "close" });
354 + }
355 + });
356 });
357 } else {
358 // We got a bad response
@@ -509,7 +523,8 @@ module.exports.CreateAmtManager = function(parent) {
523 // Care should be take not to have many pending WSMAN called when performing clock sync.
524 function attemptSyncClock(dev, func) {
525 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
512 - dev.clockSyncCompleted = func;
526 + dev.taskCount = 1;
527 + dev.taskCompleted = func;
528 dev.amtstack.AMT_TimeSynchronizationService_GetLowAccuracyTimeSynch(attemptSyncClockEx);
529 }
530
@@ -517,17 +532,19 @@ module.exports.CreateAmtManager = function(parent) {
532 function attemptSyncClockEx(stack, name, response, status) {
533 const dev = stack.dev;
534 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
520 - if (status != 200) { removeDevice(dev.nodeid); }
535 + if (status != 200) { removeDevice(dev.nodeid); return; }
536
537 // Compute how much drift between Intel AMT and our clock.
538 var t = new Date(), now = new Date();
539 t.setTime(response.Body['Ta0'] * 1000);
540 if (Math.abs(t - now) > 10000) { // If the Intel AMT clock is more than 10 seconds off, set it.
541 + dev.consoleMsg("Performing clock sync.");
542 var Tm1 = Math.round(now.getTime() / 1000);
543 dev.amtstack.AMT_TimeSynchronizationService_SetHighAccuracyTimeSynch(response.Body['Ta0'], Tm1, Tm1, attemptSyncClockSet);
544 } else {
545 // Clock is fine, we are done.
530 - if (dev.clockSyncCompleted != null) { var f = dev.clockSyncCompleted; delete dev.clockSyncCompleted; f(); }
546 + dev.consoleMsg("Clock ok.");
547 + devTaskCompleted(dev)
548 }
549 }
550
@@ -536,28 +553,37 @@ module.exports.CreateAmtManager = function(parent) {
553 const dev = stack.dev;
554 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
555 if (status != 200) { removeDevice(dev.nodeid); }
539 - if (dev.clockSyncCompleted != null) { var f = dev.clockSyncCompleted; delete dev.clockSyncCompleted; f(); }
556 + devTaskCompleted(dev)
557 }
558
542 - function attemptFetchHardwareInventory(dev) {
543 - if (obj.amtDevices[dev.nodeid] == null) return false; // Device no longer exists, ignore this request.
559 + function attemptFetchHardwareInventory(dev, func) {
560 + if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
561 const mesh = parent.webserver.meshes[dev.meshid];
545 - if (mesh == null) { removeDevice(dev.nodeid); return false; }
562 + if (mesh == null) { removeDevice(dev.nodeid); return; }
563 if (mesh.mtype == 1) { // If this is a Intel AMT only device group, pull the hardware inventory and network information for this device
564 + dev.consoleMsg("Fetching hardware inventory.");
565 + dev.taskCount = 2;
566 + dev.taskCompleted = func;
567 dev.amtstack.BatchEnum('', ['*CIM_ComputerSystemPackage', 'CIM_SystemPackaging', '*CIM_Chassis', 'CIM_Chip', '*CIM_Card', '*CIM_BIOSElement', 'CIM_Processor', 'CIM_PhysicalMemory', 'CIM_MediaAccessDevice', 'CIM_PhysicalPackage'], attemptFetchHardwareInventoryResponse);
568 dev.amtstack.BatchEnum('', ['AMT_EthernetPortSettings'], attemptFetchNetworkResponse);
549 - return true;
569 + } else {
570 + if (func) { func(); }
571 }
551 - return false;
572 + }
573 +
574 + //
575 + function devTaskCompleted(dev) {
576 + dev.taskCount--;
577 + if (dev.taskCount == 0) { var f = dev.taskCompleted; delete dev.taskCount; delete dev.taskCompleted; if (f != null) { f(); } }
578 }
579
580 function attemptFetchNetworkResponse(stack, name, responses, status) {
581 const dev = stack.dev;
582 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
557 - if (status != 200) return;
583 + if (status != 200) { devTaskCompleted(dev); return; }
584
585 //console.log(JSON.stringify(responses, null, 2));
560 - if ((responses['AMT_EthernetPortSettings'] == null) || (responses['AMT_EthernetPortSettings'].responses == null)) return;
586 + if ((responses['AMT_EthernetPortSettings'] == null) || (responses['AMT_EthernetPortSettings'].responses == null)) { devTaskCompleted(dev); return; }
587
588 // Find the wired and wireless interfaces
589 var wired = null, wireless = null;
@@ -567,7 +593,7 @@ module.exports.CreateAmtManager = function(parent) {
593 if (netif.WLANLinkProtectionLevel != null) { wireless = netif; } else { wired = netif; }
594 }
595 }
570 - if ((wired == null) && (wireless == null)) return;
596 + if ((wired == null) && (wireless == null)) { devTaskCompleted(dev); return; }
597
598 // Sent by the agent to update agent network interface information
599 var net = { netif2: {} };
@@ -601,6 +627,8 @@ module.exports.CreateAmtManager = function(parent) {
627
628 // Event the node interface information change
629 parent.DispatchEvent(parent.webserver.CreateMeshDispatchTargets(dev.meshid, [dev.nodeid]), obj, { action: 'ifchange', nodeid: dev.nodeid, domain: dev.nodeid.split('/')[1], nolog: 1 });
630 +
631 + devTaskCompleted(dev);
632 }
633
634
@@ -625,7 +653,7 @@ module.exports.CreateAmtManager = function(parent) {
653 function attemptFetchHardwareInventoryResponse(stack, name, responses, status) {
654 const dev = stack.dev;
655 if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
628 - if (status != 200) return;
656 + if (status != 200) { devTaskCompleted(dev); return; }
657
658 // Extract basic data
659 var hw = {}
@@ -648,9 +676,11 @@ module.exports.CreateAmtManager = function(parent) {
676 var m2 = {}, m = hw.PhysicalMemory[i];
677 m2.BankLabel = m.BankLabel;
678 m2.Capacity = m.Capacity;
651 - m2.PartNumber = m.PartNumber.trim();
652 - m2.SerialNumber = m.SerialNumber.trim();
653 - m2.Manufacturer = m.Manufacturer.trim();
679 + if (m.PartNumber) { m2.PartNumber = m.PartNumber.trim(); }
680 + if (typeof m.SerialNumber == 'string') { m2.SerialNumber = m.SerialNumber.trim(); }
681 + if (typeof m.SerialNumber == 'number') { m2.SerialNumber = m.SerialNumber; }
682 + if (typeof m.SerialNumber == 'string') { m2.Manufacturer = m.Manufacturer.trim(); }
683 + if (typeof m.Manufacturer == 'number') { m2.Manufacturer = m.Manufacturer; }
684 memory.push(m2);
685 }
686 hw2.hardware.windows.memory = memory;
@@ -660,21 +690,21 @@ module.exports.CreateAmtManager = function(parent) {
690 for (var i in hw.MediaAccessDevice) {
691 var m2 = {}, m = hw.MediaAccessDevice[i];
692 m2.Caption = m.DeviceID;
663 - m2.Size = (m.MaxMediaSize * 1000);
693 + if (m.MaxMediaSize) { m2.Size = (m.MaxMediaSize * 1000); }
694 drives.push(m2);
695 }
696 hw2.hardware.identifiers.storage_devices = drives;
697 }
698 if (hw.Bios != null) {
669 - hw2.hardware.identifiers.bios_vendor = hw.Bios.Manufacturer.trim();
699 + if (hw.Bios.Manufacturer) { hw2.hardware.identifiers.bios_vendor = hw.Bios.Manufacturer.trim(); }
700 hw2.hardware.identifiers.bios_version = hw.Bios.Version;
701 if (hw.Bios.ReleaseDate && hw.Bios.ReleaseDate.Datetime) { hw2.hardware.identifiers.bios_date = hw.Bios.ReleaseDate.Datetime; }
702 }
703 if (hw.PhysicalPackage != null) {
674 - hw2.hardware.identifiers.board_name = hw.Card.Model.trim();
675 - hw2.hardware.identifiers.board_vendor = hw.Card.Manufacturer.trim();
676 - hw2.hardware.identifiers.board_version = hw.Card.Version.trim();
677 - hw2.hardware.identifiers.board_serial = hw.Card.SerialNumber.trim();
704 + if (hw.Card.Model) { hw2.hardware.identifiers.board_name = hw.Card.Model.trim(); }
705 + if (hw.Card.Manufacturer) { hw2.hardware.identifiers.board_vendor = hw.Card.Manufacturer.trim(); }
706 + if (hw.Card.Version) { hw2.hardware.identifiers.board_version = hw.Card.Version.trim(); }
707 + if (hw.Card.SerialNumber) { hw2.hardware.identifiers.board_serial = hw.Card.SerialNumber.trim(); }
708 }
709 if ((hw.Chips != null) && (hw.Chips.length > 0)) {
710 for (var i in hw.Chips) {
@@ -704,6 +734,8 @@ module.exports.CreateAmtManager = function(parent) {
734 parent.DispatchEvent(parent.webserver.CreateMeshDispatchTargets(dev.meshid, [dev.nodeid]), obj, event);
735 }
736 });
737 +
738 + devTaskCompleted(dev);
739 }
740
741 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); }
mpsserver.js
+10
@@ -285,6 +285,9 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
285 socket.SetupChannel.parent = obj;
286 socket.SetupChannel.conn = socket;
287 socket.websocket = 1;
288 + socket.ControlMsg = function ControlMsg(message) { return ControlMsg.parent.SendJsonControl(ControlMsg.conn, message); }
289 + socket.ControlMsg.parent = obj;
290 + socket.ControlMsg.conn = socket;
291 parent.debug('mps', "New CIRA websocket connection");
292
293 socket.on('message', function (data) {
@@ -913,6 +916,13 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
916 for (var i in connections) { obj.close(connections[i]); }
917 };
918
919 + obj.SendJsonControl = function(socket, data) {
920 + if (socket.tag.connType == 0) return; // This command is valid only for connections that are not really CIRA.
921 + parent.debug('mpscmd', '<-- JSON_CONTROL');
922 + if (typeof data == 'object') { data = JSON.stringify(data); }
923 + Write(socket, String.fromCharCode(APFProtocol.JSON_CONTROL) + common.IntToStr(data.length) + data);
924 + }
925 +
926 function SendServiceAccept(socket, service) {
927 parent.debug('mpscmd', '<-- SERVICE_ACCEPT', service);
928 Write(socket, String.fromCharCode(APFProtocol.SERVICE_ACCEPT) + common.IntToStr(service.length) + service);
webserver.js
+3 -1
@@ -3520,6 +3520,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3520 if (ws.logfile != null) { recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd, ws) { obj.fs.close(fd); delete ws.logfile; }, ws); }
3521 });
3522
3523 + // Note that here, req.query.p: 1 = WSMAN with server auth, 2 = REDIR with server auth, 3 = WSMAN without server auth, 4 = REDIR with server auth
3524 +
3525 // Fetch Intel AMT credentials & Setup interceptor
3526 if (req.query.p == 1) {
3527 parent.debug('webrelaydata', 'INTERCEPTOR1', { host: node.host, port: port, user: node.intelamt.user, pass: node.intelamt.pass });
@@ -3587,7 +3589,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3589 // Compute target port
3590 var port = 16992;
3591 if (node.intelamt.tls > 0) port = 16993; // This is a direct connection, use TLS when possible
3590 - if (req.query.p == 2) port += 2;
3592 + if ((req.query.p == 2) || (req.query.p == 4)) port += 2;
3593
3594 if (node.intelamt.tls == 0) {
3595 // If this is TCP (without TLS) set a normal TCP socket