mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-03-09 15:40:18 +00:00
Added Intel AMT tunneling configuration support.
This commit is contained in:
parent
b555fcbe43
commit
fd8265313d
8 changed files with 709 additions and 109 deletions
|
@ -113,7 +113,7 @@ function run(argv) {
|
|||
//console.log('addedModules = ' + JSON.stringify(addedModules));
|
||||
var actionpath = 'meshaction.txt';
|
||||
if (args.actionfile != null) { actionpath = args.actionfile; }
|
||||
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'];
|
||||
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'];
|
||||
|
||||
// Load the action file
|
||||
var actionfile = null;
|
||||
|
@ -129,6 +129,7 @@ function run(argv) {
|
|||
if ((typeof args.localport) == 'string') { settings.localport = parseInt(args.localport); }
|
||||
if ((typeof args.remotenodeid) == 'string') { settings.remotenodeid = args.remotenodeid; }
|
||||
if ((typeof args.name) == 'string') { settings.name = args.name; }
|
||||
if ((typeof args.id) == 'string') { settings.id = args.id; }
|
||||
if ((typeof args.username) == 'string') { settings.username = args.username; }
|
||||
if ((typeof args.password) == 'string') { settings.password = args.password; }
|
||||
if ((typeof args.url) == 'string') { settings.url = args.url; }
|
||||
|
@ -174,6 +175,7 @@ function run(argv) {
|
|||
console.log(' meshcmd [action] [arguments...]\r\n');
|
||||
console.log('Valid MeshCentral actions:');
|
||||
console.log(' Route - Map a local TCP port to a remote computer.');
|
||||
console.log(' AmtConfig - Setup Intel AMT on this computer.');
|
||||
console.log('\r\nValid local actions:');
|
||||
console.log(' SMBios - Display System Management BIOS tables for this computer.');
|
||||
console.log(' RawSMBios - Display RAW System Management BIOS tables for this computer.');
|
||||
|
@ -245,6 +247,12 @@ function run(argv) {
|
|||
console.log(' --tag [string] Optional string sent to the server during activation.');
|
||||
console.log(' --serverhttpshash [hash] Optional TLS server certificate hash.');
|
||||
console.log(' --profile [string] Optional profile used for server activation.');
|
||||
} else if (action == 'amtconfig') {
|
||||
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]');
|
||||
console.log('\r\nPossible arguments:\r\n');
|
||||
console.log(' --url [wss://server] The address of the MeshCentral server.');
|
||||
console.log(' --id [groupid] The device group identifier.');
|
||||
console.log(' --serverhttpshash [hash] Optional TLS server certificate hash.');
|
||||
} else if (action == 'amtacm') {
|
||||
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]');
|
||||
console.log('\r\nPossible arguments:\r\n');
|
||||
|
@ -643,6 +651,12 @@ function run(argv) {
|
|||
settings.localport = 16992;
|
||||
debug(1, "Settings: " + JSON.stringify(settings));
|
||||
getAmtUuid();
|
||||
} else if (settings.action == 'amtconfig') {
|
||||
// Start Intel AMT configuration
|
||||
if ((settings.url == null) || (typeof settings.url != 'string') || (settings.url == '')) { console.log('No MeshCentral server URL specified, use --url [url].'); exit(1); return; }
|
||||
if ((settings.id == null) || (typeof settings.id != 'string') || (settings.id == '')) { console.log('No device group identifier specified, use --id [identifier].'); exit(1); return; }
|
||||
debug(1, "Settings: " + JSON.stringify(settings));
|
||||
configureAmt();
|
||||
} else if (settings.action == 'amtccm') {
|
||||
// Start activation to CCM
|
||||
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() {
|
|||
}
|
||||
|
||||
|
||||
//
|
||||
// Configure Intel AMT
|
||||
//
|
||||
|
||||
function configureAmt() {
|
||||
console.log('Starting Intel AMT configuration...');
|
||||
settings.noconsole = true;
|
||||
|
||||
// Display Intel AMT version and activation state
|
||||
mestate = {};
|
||||
var amtMeiModule, amtMei;
|
||||
try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { console.log(ex); exit(1); return; }
|
||||
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
|
||||
amtMei.getProvisioningState(function (result) { if (result) { mestate.ProvisioningState = result; } });
|
||||
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; } } });
|
||||
amtMei.getLanInterfaceSettings(0, function (result) { if (result) { mestate.net0 = result; } });
|
||||
amtMei.getUuid(function (result) { if ((result != null) && (result.uuid != null)) { mestate.uuid = result.uuid; } });
|
||||
amtMei.getControlMode(function (result) { if (result != null) { mestate.controlMode = result.controlMode; } }); // controlMode: 0 = NoActivated, 1 = CCM, 2 = ACM
|
||||
amtMei.getDnsSuffix(function (result) {
|
||||
if ((mestate.vers == null) || (mestate.vers['AMT'] == null)) { console.log("Unable to get Intel AMT version."); exit(100); return; }
|
||||
if (mestate.ProvisioningState == null) { console.log("Unable to read Intel AMT activation state."); exit(100); return; }
|
||||
//if ((settings.action != 'amtdiscover') && (mestate.controlMode == 2)) { console.log("Intel AMT already activation in admin control mode."); exit(100); return; }
|
||||
if (mestate.uuid == null) { console.log("Unable to get Intel AMT UUID."); exit(100); return; }
|
||||
var fqdn = null;
|
||||
//if ((mestate.net0 == null) && (meinfo.net0.enabled != 0)) { console.log("No Intel AMT wired interface, can't perform ACM activation."); exit(100); return; }
|
||||
if (result) { fqdn = result; } // If Intel AMT has a trusted DNS suffix set, use that one.
|
||||
else {
|
||||
// Look for the DNS suffix for the Intel AMT Ethernet interface
|
||||
var interfaces = require('os').networkInterfaces();
|
||||
for (var i in interfaces) {
|
||||
for (var j in interfaces[i]) {
|
||||
if ((interfaces[i][j].mac == mestate.net0.mac) && (interfaces[i][j].fqdn != null) && (interfaces[i][j].fqdn != '')) { fqdn = interfaces[i][j].fqdn; }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fqdn != null) { settings.fqdn = fqdn; settings.uuid = mestate.uuid; }
|
||||
getTrustedHashes(amtMei, function () { startLms(configureAmt2, amtMei); });
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function configureAmt2() {
|
||||
// Connect to MPS and start APF relay
|
||||
var apfarg = {
|
||||
mpsurl: settings.url,
|
||||
mpsuser: settings.id.substring(0, 16),
|
||||
mpspass: settings.id.substring(0, 16),
|
||||
mpskeepalive: 60000,
|
||||
clientname: require('os').hostname(),
|
||||
clientaddress: '127.0.0.1',
|
||||
clientuuid: mestate.uuid,
|
||||
conntype: 2 // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay.
|
||||
};
|
||||
if ((apfarg.clientuuid == null) || (apfarg.clientuuid.length != 36)) {
|
||||
console.log("Unable to get Intel AMT UUID: " + apfarg.clientuuid);
|
||||
exit(1); return;
|
||||
} else {
|
||||
settings.apftunnel = require('apfclient')({ debug: (settings.debuglevel > 0) }, apfarg);
|
||||
settings.apftunnel.onJsonControl = configureJsonControl;
|
||||
settings.apftunnel.onChannelClosed = function () { exit(0); }
|
||||
try {
|
||||
settings.apftunnel.connect();
|
||||
console.log("Started APF tunnel...");
|
||||
} catch (e) {
|
||||
console.log(JSON.stringify(e));
|
||||
exit(1); return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function configureJsonControl(data) {
|
||||
switch (data.action) {
|
||||
case 'console':
|
||||
console.log(data.msg);
|
||||
break;
|
||||
case 'close':
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Deactivate Intel AMT CCM
|
||||
//
|
||||
|
|
|
@ -2563,7 +2563,7 @@ function createMeshCore(agent) {
|
|||
var response = null;
|
||||
switch (cmd) {
|
||||
case 'help': { // Displays available commands
|
||||
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';
|
||||
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';
|
||||
if (process.platform == 'win32') { availcommands += ',safemode,wpfhwacceleration,uac'; }
|
||||
if (process.platform != 'freebsd') { availcommands += ',vm';}
|
||||
if (require('MeshAgent').maxKvmTileSize != null) { availcommands += ',kvmmode'; }
|
||||
|
@ -3540,6 +3540,29 @@ function createMeshCore(agent) {
|
|||
if (diag) { diag.close(); diag = null; }
|
||||
break;
|
||||
}
|
||||
case 'amtconfig': {
|
||||
if (meshCoreObj.intelamt == null) { response = "No Intel AMT support delected"; break; }
|
||||
if (apftunnel != null) { response = "Intel AMT server tunnel already active"; break; }
|
||||
var apfarg = {
|
||||
mpsurl: mesh.ServerUrl.replace('agent.ashx', 'apf.ashx'),
|
||||
mpsuser: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
|
||||
mpspass: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
|
||||
mpskeepalive: 60000,
|
||||
clientname: require('os').hostname(),
|
||||
clientaddress: '127.0.0.1',
|
||||
clientuuid: meshCoreObj.intelamt.uuid,
|
||||
conntype: 2 // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay, other values for testing.
|
||||
};
|
||||
if ((apfarg.clientuuid == null) || (apfarg.clientuuid.length != 36)) { response = "Unable to get Intel AMT UUID"; break; }
|
||||
apftunnel = require('apfclient')({ debug: false }, apfarg);
|
||||
apftunnel.onJsonControl = function (data) {
|
||||
if (data.action == 'console') { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: data.msg }); }
|
||||
if (data.action == 'close') { try { apftunnel.disconnect(); } catch (e) { } apftunnel = null; }
|
||||
}
|
||||
apftunnel.onChannelClosed = function () { apftunnel = null; }
|
||||
try { apftunnel.connect(); response = "Started Intel AMT configuration"; } catch (ex) { response = JSON.stringify(ex); }
|
||||
break;
|
||||
}
|
||||
case 'apf': {
|
||||
if (meshCoreObj.intelamt !== null) {
|
||||
if (args['_'].length == 1) {
|
||||
|
@ -3562,8 +3585,12 @@ function createMeshCore(agent) {
|
|||
if ((apfarg.clientuuid == null) || (apfarg.clientuuid.length != 36)) {
|
||||
response = "Unable to get Intel AMT UUID: " + apfarg.clientuuid;
|
||||
} else {
|
||||
var tobj = { debug: false };
|
||||
apftunnel = require('apfclient')(tobj, apfarg);
|
||||
apftunnel = require('apfclient')({ debug: false }, apfarg);
|
||||
apftunnel.onJsonControl = function (data) {
|
||||
if (data.action == 'console') { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: data.msg }); }
|
||||
if (data.action == 'close') { try { apftunnel.disconnect(); } catch (e) { } apftunnel = null; }
|
||||
}
|
||||
apftunnel.onChannelClosed = function () { apftunnel = null; }
|
||||
try {
|
||||
apftunnel.connect();
|
||||
response = "Started APF tunnel";
|
||||
|
|
450
agents/modules_meshcmd/apfclient.js
Normal file
450
agents/modules_meshcmd/apfclient.js
Normal file
|
@ -0,0 +1,450 @@
|
|||
/*
|
||||
Copyright 2018-2020 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description APF/CIRA Client for Duktape
|
||||
* @author Joko Sastriawan & Ylian Saint-Hilaire
|
||||
* @copyright Intel Corporation 2020
|
||||
* @license Apache-2.0
|
||||
* @version v0.0.2
|
||||
*/
|
||||
|
||||
function CreateAPFClient(parent, args) {
|
||||
if ((args.clientuuid == null) || (args.clientuuid.length != 36)) return null; // Require a UUID if this exact length
|
||||
|
||||
var obj = {};
|
||||
obj.parent = parent;
|
||||
obj.args = args;
|
||||
obj.http = require('http');
|
||||
obj.net = require('net');
|
||||
obj.forwardClient = null;
|
||||
obj.downlinks = {};
|
||||
obj.pfwd_idx = 0;
|
||||
obj.timer = null; // Keep alive timer
|
||||
|
||||
// obj.onChannelClosed
|
||||
// obj.onJsonControl
|
||||
|
||||
// Function copied from common.js
|
||||
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.
|
||||
function IntToStr(v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); };
|
||||
function hex2rstr(d) { var r = '', m = ('' + d).match(/../g), t; while (t = m.shift()) { r += String.fromCharCode('0x' + t); } return r; };
|
||||
function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); }; // Convert decimal to hex
|
||||
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
|
||||
function d2h(d) { return (d / 256 + 1 / 512).toString(16).substring(2, 4); }
|
||||
function buf2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += d2h(input[i]); } return r; };
|
||||
function Debug(str) { if (obj.parent.debug) { console.log(str); } }
|
||||
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); }
|
||||
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; }
|
||||
function binzerostring(len) { var res = ''; for (var l = 0; l < len; l++) { res += String.fromCharCode(0 & 0xFF); } return res; }
|
||||
|
||||
// CIRA state
|
||||
var CIRASTATE = {
|
||||
INITIAL: 0,
|
||||
PROTOCOL_VERSION_SENT: 1,
|
||||
AUTH_SERVICE_REQUEST_SENT: 2,
|
||||
AUTH_REQUEST_SENT: 3,
|
||||
PFWD_SERVICE_REQUEST_SENT: 4,
|
||||
GLOBAL_REQUEST_SENT: 5,
|
||||
FAILED: -1
|
||||
}
|
||||
obj.cirastate = CIRASTATE.INITIAL;
|
||||
|
||||
// REDIR state
|
||||
var REDIR_TYPE = {
|
||||
REDIR_UNKNOWN: 0,
|
||||
REDIR_SOL: 1,
|
||||
REDIR_KVM: 2,
|
||||
REDIR_IDER: 3
|
||||
}
|
||||
|
||||
// redirection start command
|
||||
obj.RedirectStartSol = String.fromCharCode(0x10, 0x00, 0x00, 0x00, 0x53, 0x4F, 0x4C, 0x20);
|
||||
obj.RedirectStartKvm = String.fromCharCode(0x10, 0x01, 0x00, 0x00, 0x4b, 0x56, 0x4d, 0x52);
|
||||
obj.RedirectStartIder = String.fromCharCode(0x10, 0x00, 0x00, 0x00, 0x49, 0x44, 0x45, 0x52);
|
||||
|
||||
// Intel AMT forwarded port list for non-TLS mode
|
||||
//var pfwd_ports = [16992, 623, 16994, 5900];
|
||||
var pfwd_ports = [ 16992, 16993 ];
|
||||
|
||||
// protocol definitions
|
||||
var APFProtocol = {
|
||||
UNKNOWN: 0,
|
||||
DISCONNECT: 1,
|
||||
SERVICE_REQUEST: 5,
|
||||
SERVICE_ACCEPT: 6,
|
||||
USERAUTH_REQUEST: 50,
|
||||
USERAUTH_FAILURE: 51,
|
||||
USERAUTH_SUCCESS: 52,
|
||||
GLOBAL_REQUEST: 80,
|
||||
REQUEST_SUCCESS: 81,
|
||||
REQUEST_FAILURE: 82,
|
||||
CHANNEL_OPEN: 90,
|
||||
CHANNEL_OPEN_CONFIRMATION: 91,
|
||||
CHANNEL_OPEN_FAILURE: 92,
|
||||
CHANNEL_WINDOW_ADJUST: 93,
|
||||
CHANNEL_DATA: 94,
|
||||
CHANNEL_CLOSE: 97,
|
||||
PROTOCOLVERSION: 192,
|
||||
KEEPALIVE_REQUEST: 208,
|
||||
KEEPALIVE_REPLY: 209,
|
||||
KEEPALIVE_OPTIONS_REQUEST: 210,
|
||||
KEEPALIVE_OPTIONS_REPLY: 211,
|
||||
JSON_CONTROL: 250 // This is a Mesh specific command that sends JSON to and from the MPS server.
|
||||
}
|
||||
|
||||
var APFDisconnectCode = {
|
||||
HOST_NOT_ALLOWED_TO_CONNECT: 1,
|
||||
PROTOCOL_ERROR: 2,
|
||||
KEY_EXCHANGE_FAILED: 3,
|
||||
RESERVED: 4,
|
||||
MAC_ERROR: 5,
|
||||
COMPRESSION_ERROR: 6,
|
||||
SERVICE_NOT_AVAILABLE: 7,
|
||||
PROTOCOL_VERSION_NOT_SUPPORTED: 8,
|
||||
HOST_KEY_NOT_VERIFIABLE: 9,
|
||||
CONNECTION_LOST: 10,
|
||||
BY_APPLICATION: 11,
|
||||
TOO_MANY_CONNECTIONS: 12,
|
||||
AUTH_CANCELLED_BY_USER: 13,
|
||||
NO_MORE_AUTH_METHODS_AVAILABLE: 14,
|
||||
INVALID_CREDENTIALS: 15,
|
||||
CONNECTION_TIMED_OUT: 16,
|
||||
BY_POLICY: 17,
|
||||
TEMPORARILY_UNAVAILABLE: 18
|
||||
}
|
||||
|
||||
var APFChannelOpenFailCodes = {
|
||||
ADMINISTRATIVELY_PROHIBITED: 1,
|
||||
CONNECT_FAILED: 2,
|
||||
UNKNOWN_CHANNEL_TYPE: 3,
|
||||
RESOURCE_SHORTAGE: 4,
|
||||
}
|
||||
|
||||
var APFChannelOpenFailureReasonCode = {
|
||||
AdministrativelyProhibited: 1,
|
||||
ConnectFailed: 2,
|
||||
UnknownChannelType: 3,
|
||||
ResourceShortage: 4,
|
||||
}
|
||||
|
||||
obj.onSecureConnect = function onSecureConnect(resp, ws, head) {
|
||||
Debug("APF Secure WebSocket connected.");
|
||||
//console.log(JSON.stringify(resp));
|
||||
obj.forwardClient.tag = { accumulator: [] };
|
||||
obj.forwardClient.ws = ws;
|
||||
obj.forwardClient.ws.on('end', function () {
|
||||
Debug("APF: Connection is closing.");
|
||||
if (obj.timer != null) { clearInterval(obj.timer); obj.timer = null; }
|
||||
if (obj.onChannelClosed) { obj.onChannelClosed(obj); }
|
||||
});
|
||||
|
||||
obj.forwardClient.ws.on('data', function (data) {
|
||||
obj.forwardClient.tag.accumulator += hex2rstr(buf2hex(data));
|
||||
try {
|
||||
var len = 0;
|
||||
do {
|
||||
len = ProcessData(obj.forwardClient);
|
||||
if (len > 0) { obj.forwardClient.tag.accumulator = obj.forwardClient.tag.accumulator.slice(len); }
|
||||
if (obj.cirastate == CIRASTATE.FAILED) {
|
||||
Debug("APF: in a failed state, destroying socket.");
|
||||
obj.forwardClient.ws.end();
|
||||
}
|
||||
} while (len > 0);
|
||||
} catch (ex) { Debug(ex); }
|
||||
});
|
||||
|
||||
obj.forwardClient.ws.on('error', function (e) {
|
||||
Debug("APF: Connection error, ending connecting.");
|
||||
if (obj.timer != null) { clearInterval(obj.timer); obj.timer = null; }
|
||||
});
|
||||
|
||||
obj.state = CIRASTATE.INITIAL;
|
||||
if ((typeof obj.args.conntype == 'number') && (obj.args.conntype != 0)) { SendJsonControl(obj.forwardClient.ws, { action: 'connType', value: obj.args.conntype } ); }
|
||||
SendProtocolVersion(obj.forwardClient.ws, obj.args.clientuuid);
|
||||
SendServiceRequest(obj.forwardClient.ws, 'auth@amt.intel.com');
|
||||
}
|
||||
|
||||
function SendJsonControl(socket, o) {
|
||||
var data = JSON.stringify(o)
|
||||
socket.write(String.fromCharCode(APFProtocol.JSON_CONTROL) + IntToStr(data.length) + data);
|
||||
Debug("APF: Send JSON control: " + data);
|
||||
}
|
||||
|
||||
function SendProtocolVersion(socket, uuid) {
|
||||
var data = String.fromCharCode(APFProtocol.PROTOCOLVERSION) + IntToStr(1) + IntToStr(0) + IntToStr(0) + hex2rstr(strToGuid(uuid)) + binzerostring(64);
|
||||
socket.write(data);
|
||||
Debug("APF: Send protocol version 1 0 " + uuid);
|
||||
obj.cirastate = CIRASTATE.PROTOCOL_VERSION_SENT;
|
||||
}
|
||||
|
||||
function SendServiceRequest(socket, service) {
|
||||
var data = String.fromCharCode(APFProtocol.SERVICE_REQUEST) + IntToStr(service.length) + service;
|
||||
socket.write(data);
|
||||
Debug("APF: Send service request " + service);
|
||||
if (service == 'auth@amt.intel.com') {
|
||||
obj.cirastate = CIRASTATE.AUTH_SERVICE_REQUEST_SENT;
|
||||
} else if (service == 'pfwd@amt.intel.com') {
|
||||
obj.cirastate = CIRASTATE.PFWD_SERVICE_REQUEST_SENT;
|
||||
}
|
||||
}
|
||||
|
||||
function SendUserAuthRequest(socket, user, pass) {
|
||||
var service = "pfwd@amt.intel.com";
|
||||
var data = String.fromCharCode(APFProtocol.USERAUTH_REQUEST) + IntToStr(user.length) + user + IntToStr(service.length) + service;
|
||||
//password auth
|
||||
data += IntToStr(8) + 'password';
|
||||
data += binzerostring(1) + IntToStr(pass.length) + pass;
|
||||
socket.write(data);
|
||||
Debug("APF: Send username password authentication to MPS");
|
||||
obj.cirastate = CIRASTATE.AUTH_REQUEST_SENT;
|
||||
}
|
||||
|
||||
function SendGlobalRequestPfwd(socket, amthostname, amtport) {
|
||||
var tcpipfwd = 'tcpip-forward';
|
||||
var data = String.fromCharCode(APFProtocol.GLOBAL_REQUEST) + IntToStr(tcpipfwd.length) + tcpipfwd + binzerostring(1, 1);
|
||||
data += IntToStr(amthostname.length) + amthostname + IntToStr(amtport);
|
||||
socket.write(data);
|
||||
Debug("APF: Send tcpip-forward " + amthostname + ":" + amtport);
|
||||
obj.cirastate = CIRASTATE.GLOBAL_REQUEST_SENT;
|
||||
}
|
||||
|
||||
function SendKeepAliveRequest(socket) {
|
||||
socket.write(String.fromCharCode(APFProtocol.KEEPALIVE_REQUEST) + IntToStr(255));
|
||||
Debug("APF: Send keepalive request");
|
||||
}
|
||||
|
||||
function SendKeepAliveReply(socket, cookie) {
|
||||
socket.write(String.fromCharCode(APFProtocol.KEEPALIVE_REPLY) + IntToStr(cookie));
|
||||
Debug("APF: Send keepalive reply");
|
||||
}
|
||||
|
||||
function ProcessData(socket) {
|
||||
var cmd = socket.tag.accumulator.charCodeAt(0);
|
||||
var len = socket.tag.accumulator.length;
|
||||
var data = socket.tag.accumulator;
|
||||
if (len == 0) { return 0; }
|
||||
|
||||
// Respond to MPS according to obj.cirastate
|
||||
switch (cmd) {
|
||||
case APFProtocol.SERVICE_ACCEPT: {
|
||||
var slen = ReadInt(data, 1), service = data.substring(5, 6 + slen);
|
||||
Debug("APF: Service request to " + service + " accepted.");
|
||||
if (service == 'auth@amt.intel.com') {
|
||||
if (obj.cirastate >= CIRASTATE.AUTH_SERVICE_REQUEST_SENT) {
|
||||
SendUserAuthRequest(socket.ws, obj.args.mpsuser, obj.args.mpspass);
|
||||
}
|
||||
} else if (service == 'pfwd@amt.intel.com') {
|
||||
if (obj.cirastate >= CIRASTATE.PFWD_SERVICE_REQUEST_SENT) {
|
||||
SendGlobalRequestPfwd(socket.ws, obj.args.clientname, pfwd_ports[obj.pfwd_idx++]);
|
||||
}
|
||||
}
|
||||
return 5 + slen;
|
||||
}
|
||||
case APFProtocol.REQUEST_SUCCESS: {
|
||||
if (len >= 5) {
|
||||
var port = ReadInt(data, 1);
|
||||
Debug("APF: Request to port forward " + port + " successful.");
|
||||
// iterate to pending port forward request
|
||||
if (obj.pfwd_idx < pfwd_ports.length) {
|
||||
SendGlobalRequestPfwd(socket.ws, obj.args.clientname, pfwd_ports[obj.pfwd_idx++]);
|
||||
} else {
|
||||
// no more port forward, now setup timer to send keep alive
|
||||
Debug("APF: Start keep alive for every " + obj.args.mpskeepalive + " ms.");
|
||||
obj.timer = setInterval(function () {
|
||||
SendKeepAliveRequest(obj.forwardClient.ws);
|
||||
}, obj.args.mpskeepalive);//
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
Debug("APF: Request successful.");
|
||||
return 1;
|
||||
}
|
||||
case APFProtocol.USERAUTH_SUCCESS: {
|
||||
Debug("APF: User Authentication successful");
|
||||
// Send Pfwd service request
|
||||
SendServiceRequest(socket.ws, 'pfwd@amt.intel.com');
|
||||
return 1;
|
||||
}
|
||||
case APFProtocol.USERAUTH_FAILURE: {
|
||||
Debug("APF: User Authentication failed");
|
||||
obj.cirastate = CIRASTATE.FAILED;
|
||||
return 14;
|
||||
}
|
||||
case APFProtocol.KEEPALIVE_REQUEST: {
|
||||
Debug("APF: Keep Alive Request with cookie: " + ReadInt(data, 1));
|
||||
SendKeepAliveReply(socket.ws, ReadInt(data, 1));
|
||||
return 5;
|
||||
}
|
||||
case APFProtocol.KEEPALIVE_REPLY: {
|
||||
Debug("APF: Keep Alive Reply with cookie: " + ReadInt(data, 1));
|
||||
return 5;
|
||||
}
|
||||
// Channel management
|
||||
case APFProtocol.CHANNEL_OPEN: {
|
||||
// Parse CHANNEL OPEN request
|
||||
var p_res = parseChannelOpen(data);
|
||||
Debug("APF: CHANNEL_OPEN request: " + JSON.stringify(p_res));
|
||||
// Check if target port is in pfwd_ports
|
||||
if (pfwd_ports.indexOf(p_res.target_port) >= 0) {
|
||||
// Connect socket to that port
|
||||
var chan = obj.net.createConnection({ host: obj.args.clientaddress, port: p_res.target_port }, function () {
|
||||
//require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: "CHANNEL_OPEN-open" });
|
||||
// obj.downlinks[p_res.sender_chan].setEncoding('binary');//assume everything is binary, not interpreting
|
||||
SendChannelOpenConfirm(socket.ws, p_res);
|
||||
});
|
||||
|
||||
// Setup flow control
|
||||
chan.maxInWindow = p_res.window_size; // Oddly, we are using the same window size as the other side.
|
||||
chan.curInWindow = 0;
|
||||
|
||||
chan.on('data', function (ddata) {
|
||||
// Relay data to fordwardclient
|
||||
// TODO: Implement flow control
|
||||
SendChannelData(socket.ws, p_res.sender_chan, ddata);
|
||||
});
|
||||
|
||||
chan.on('error', function (e) {
|
||||
Debug("Downlink connection error: " + e);
|
||||
});
|
||||
|
||||
chan.on('end', function () {
|
||||
var chan = obj.downlinks[p_res.sender_chan];
|
||||
if (chan != null) {
|
||||
Debug("Socket ends.");
|
||||
try { SendChannelClose(socket.ws, p_res.sender_chan); } catch (ex) { }
|
||||
delete obj.downlinks[p_res.sender_chan];
|
||||
}
|
||||
});
|
||||
|
||||
obj.downlinks[p_res.sender_chan] = chan;
|
||||
} else {
|
||||
// Not a supported port, fail the connection
|
||||
SendChannelOpenFailure(socket.ws, p_res);
|
||||
}
|
||||
return p_res.len;
|
||||
}
|
||||
case APFProtocol.CHANNEL_OPEN_CONFIRMATION: {
|
||||
Debug("APF: CHANNEL_OPEN_CONFIRMATION");
|
||||
return 17;
|
||||
}
|
||||
case APFProtocol.CHANNEL_CLOSE: {
|
||||
var rcpt_chan = ReadInt(data, 1);
|
||||
Debug("APF: CHANNEL_CLOSE: " + rcpt_chan);
|
||||
try { obj.downlinks[rcpt_chan].end(); } catch (ex) { }
|
||||
return 5;
|
||||
}
|
||||
case APFProtocol.CHANNEL_DATA: {
|
||||
Debug("APF: CHANNEL_DATA: " + JSON.stringify(rstr2hex(data)));
|
||||
var rcpt_chan = ReadInt(data, 1);
|
||||
var chan_data_len = ReadInt(data, 5);
|
||||
var chan_data = data.substring(9, 9 + chan_data_len);
|
||||
var chan = obj.downlinks[rcpt_chan];
|
||||
if (chan != null) {
|
||||
chan.curInWindow += chan_data_len;
|
||||
try {
|
||||
chan.write(Buffer.from(chan_data, 'binary'), function () {
|
||||
Debug("Write completed.");
|
||||
// If the incoming window is over half used, send an adjust.
|
||||
if (this.curInWindow > (this.maxInWindow / 2)) { SendChannelWindowAdjust(socket.ws, rcpt_chan, this.curInWindow); this.curInWindow = 0; }
|
||||
});
|
||||
} catch (ex) { Debug("Cannot forward data to downlink socket."); }
|
||||
}
|
||||
return 9 + chan_data_len;
|
||||
}
|
||||
case APFProtocol.CHANNEL_WINDOW_ADJUST: {
|
||||
Debug("APF: CHANNEL_WINDOW_ADJUST");
|
||||
return 9;
|
||||
}
|
||||
case APFProtocol.JSON_CONTROL: {
|
||||
Debug("APF: JSON_CONTROL");
|
||||
var len = ReadInt(data, 1);
|
||||
if (obj.onJsonControl) { var o = null; try { o = JSON.parse(data.substring(5, 5 + len)); } catch (ex) { } if (o != null) { obj.onJsonControl(o); } }
|
||||
return 5 + len;
|
||||
}
|
||||
default: {
|
||||
Debug("CMD: " + cmd + " is not implemented.");
|
||||
obj.cirastate = CIRASTATE.FAILED;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseChannelOpen(data) {
|
||||
var result = { cmd: APFProtocol.CHANNEL_OPEN };
|
||||
var chan_type_slen = ReadInt(data, 1);
|
||||
result.chan_type = data.substring(5, 5 + chan_type_slen);
|
||||
result.sender_chan = ReadInt(data, 5 + chan_type_slen);
|
||||
result.window_size = ReadInt(data, 9 + chan_type_slen);
|
||||
var c_len = ReadInt(data, 17 + chan_type_slen);
|
||||
result.target_address = data.substring(21 + chan_type_slen, 21 + chan_type_slen + c_len);
|
||||
result.target_port = ReadInt(data, 21 + chan_type_slen + c_len);
|
||||
var o_len = ReadInt(data, 25 + chan_type_slen + c_len);
|
||||
result.origin_address = data.substring(29 + chan_type_slen + c_len, 29 + chan_type_slen + c_len + o_len);
|
||||
result.origin_port = ReadInt(data, 29 + chan_type_slen + c_len + o_len);
|
||||
result.len = 33 + chan_type_slen + c_len + o_len;
|
||||
return result;
|
||||
}
|
||||
|
||||
function SendChannelOpenFailure(socket, chan_data) {
|
||||
socket.write(String.fromCharCode(APFProtocol.CHANNEL_OPEN_FAILURE) + IntToStr(chan_data.sender_chan) + IntToStr(2) + IntToStr(0) + IntToStr(0));
|
||||
Debug("APF: Send ChannelOpenFailure");
|
||||
}
|
||||
|
||||
function SendChannelOpenConfirm(socket, chan_data) {
|
||||
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));
|
||||
Debug("APF: Send ChannelOpenConfirmation");
|
||||
}
|
||||
|
||||
function SendChannelWindowAdjust(socket, chan, size) {
|
||||
socket.write(String.fromCharCode(APFProtocol.CHANNEL_WINDOW_ADJUST) + IntToStr(chan) + IntToStr(size));
|
||||
Debug("APF: Send ChannelWindowAdjust, channel: " + chan + ", size: " + size);
|
||||
}
|
||||
|
||||
function SendChannelData(socket, chan, data) {
|
||||
socket.write(Buffer.concat([Buffer.from(String.fromCharCode(APFProtocol.CHANNEL_DATA) + IntToStr(chan) + IntToStr(data.length), 'binary'), data]));
|
||||
Debug("APF: Send ChannelData: " + data.toString('hex'));
|
||||
}
|
||||
|
||||
function SendChannelClose(socket, chan) {
|
||||
socket.write(String.fromCharCode(APFProtocol.CHANNEL_CLOSE) + IntToStr(chan));
|
||||
Debug("APF: Send ChannelClose ");
|
||||
}
|
||||
|
||||
obj.connect = function () {
|
||||
if (obj.forwardClient != null) {
|
||||
try { obj.forwardClient.ws.end(); } catch (ex) { Debug(ex); }
|
||||
//obj.forwardClient = null;
|
||||
}
|
||||
obj.cirastate = CIRASTATE.INITIAL;
|
||||
obj.pfwd_idx = 0;
|
||||
|
||||
//obj.forwardClient = new obj.ws(obj.args.mpsurl, obj.tlsoptions);
|
||||
//obj.forwardClient.on("open", obj.onSecureConnect);
|
||||
|
||||
var wsoptions = obj.http.parseUri(obj.args.mpsurl);
|
||||
wsoptions.rejectUnauthorized = 0;
|
||||
obj.forwardClient = obj.http.request(wsoptions);
|
||||
obj.forwardClient.upgrade = obj.onSecureConnect;
|
||||
obj.forwardClient.end(); // end request, trigger completion of HTTP request
|
||||
}
|
||||
|
||||
obj.disconnect = function () { try { obj.forwardClient.ws.end(); } catch (ex) { Debug(ex); } }
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
module.exports = CreateAPFClient;
|
|
@ -35,6 +35,9 @@ function CreateAPFClient(parent, args) {
|
|||
obj.pfwd_idx = 0;
|
||||
obj.timer = null; // Keep alive timer
|
||||
|
||||
// obj.onChannelClosed
|
||||
// obj.onJsonControl
|
||||
|
||||
// Function copied from common.js
|
||||
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.
|
||||
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) {
|
|||
}
|
||||
|
||||
obj.onSecureConnect = function onSecureConnect(resp, ws, head) {
|
||||
//Debug("APF Secure WebSocket connected.");
|
||||
Debug("APF Secure WebSocket connected.");
|
||||
//console.log(JSON.stringify(resp));
|
||||
obj.forwardClient.tag = { accumulator: [] };
|
||||
obj.forwardClient.ws = ws;
|
||||
obj.forwardClient.ws.on('end', function () {
|
||||
//Debug("APF: Connection is closing.");
|
||||
if (obj.timer != null) {
|
||||
clearInterval(obj.timer);
|
||||
obj.timer = null;
|
||||
}
|
||||
Debug("APF: Connection is closing.");
|
||||
if (obj.timer != null) { clearInterval(obj.timer); obj.timer = null; }
|
||||
if (obj.onChannelClosed) { obj.onChannelClosed(obj); }
|
||||
});
|
||||
|
||||
obj.forwardClient.ws.on('data', function (data) {
|
||||
|
@ -159,21 +160,16 @@ function CreateAPFClient(parent, args) {
|
|||
len = ProcessData(obj.forwardClient);
|
||||
if (len > 0) { obj.forwardClient.tag.accumulator = obj.forwardClient.tag.accumulator.slice(len); }
|
||||
if (obj.cirastate == CIRASTATE.FAILED) {
|
||||
//Debug("APF: in a failed state, destroying socket.");
|
||||
Debug("APF: in a failed state, destroying socket.");
|
||||
obj.forwardClient.ws.end();
|
||||
}
|
||||
} while (len > 0);
|
||||
} catch (e) {
|
||||
Debug(e);
|
||||
}
|
||||
} catch (ex) { Debug(ex); }
|
||||
});
|
||||
|
||||
obj.forwardClient.ws.on('error', function (e) {
|
||||
//Debug("APF: Connection error, ending connecting.");
|
||||
if (obj.timer != null) {
|
||||
clearInterval(obj.timer);
|
||||
obj.timer = null;
|
||||
}
|
||||
Debug("APF: Connection error, ending connecting.");
|
||||
if (obj.timer != null) { clearInterval(obj.timer); obj.timer = null; }
|
||||
});
|
||||
|
||||
obj.state = CIRASTATE.INITIAL;
|
||||
|
@ -185,20 +181,20 @@ function CreateAPFClient(parent, args) {
|
|||
function SendJsonControl(socket, o) {
|
||||
var data = JSON.stringify(o)
|
||||
socket.write(String.fromCharCode(APFProtocol.JSON_CONTROL) + IntToStr(data.length) + data);
|
||||
//Debug("APF: Send JSON control: " + data);
|
||||
Debug("APF: Send JSON control: " + data);
|
||||
}
|
||||
|
||||
function SendProtocolVersion(socket, uuid) {
|
||||
var data = String.fromCharCode(APFProtocol.PROTOCOLVERSION) + IntToStr(1) + IntToStr(0) + IntToStr(0) + hex2rstr(strToGuid(uuid)) + binzerostring(64);
|
||||
socket.write(data);
|
||||
//Debug("APF: Send protocol version 1 0 " + uuid);
|
||||
Debug("APF: Send protocol version 1 0 " + uuid);
|
||||
obj.cirastate = CIRASTATE.PROTOCOL_VERSION_SENT;
|
||||
}
|
||||
|
||||
function SendServiceRequest(socket, service) {
|
||||
var data = String.fromCharCode(APFProtocol.SERVICE_REQUEST) + IntToStr(service.length) + service;
|
||||
socket.write(data);
|
||||
//Debug("APF: Send service request " + service);
|
||||
Debug("APF: Send service request " + service);
|
||||
if (service == 'auth@amt.intel.com') {
|
||||
obj.cirastate = CIRASTATE.AUTH_SERVICE_REQUEST_SENT;
|
||||
} else if (service == 'pfwd@amt.intel.com') {
|
||||
|
@ -213,7 +209,7 @@ function CreateAPFClient(parent, args) {
|
|||
data += IntToStr(8) + 'password';
|
||||
data += binzerostring(1) + IntToStr(pass.length) + pass;
|
||||
socket.write(data);
|
||||
//Debug("APF: Send username password authentication to MPS");
|
||||
Debug("APF: Send username password authentication to MPS");
|
||||
obj.cirastate = CIRASTATE.AUTH_REQUEST_SENT;
|
||||
}
|
||||
|
||||
|
@ -222,18 +218,18 @@ function CreateAPFClient(parent, args) {
|
|||
var data = String.fromCharCode(APFProtocol.GLOBAL_REQUEST) + IntToStr(tcpipfwd.length) + tcpipfwd + binzerostring(1, 1);
|
||||
data += IntToStr(amthostname.length) + amthostname + IntToStr(amtport);
|
||||
socket.write(data);
|
||||
//Debug("APF: Send tcpip-forward " + amthostname + ":" + amtport);
|
||||
Debug("APF: Send tcpip-forward " + amthostname + ":" + amtport);
|
||||
obj.cirastate = CIRASTATE.GLOBAL_REQUEST_SENT;
|
||||
}
|
||||
|
||||
function SendKeepAliveRequest(socket) {
|
||||
socket.write(String.fromCharCode(APFProtocol.KEEPALIVE_REQUEST) + IntToStr(255));
|
||||
//Debug("APF: Send keepalive request");
|
||||
Debug("APF: Send keepalive request");
|
||||
}
|
||||
|
||||
function SendKeepAliveReply(socket, cookie) {
|
||||
socket.write(String.fromCharCode(APFProtocol.KEEPALIVE_REPLY) + IntToStr(cookie));
|
||||
//Debug("APF: Send keepalive reply");
|
||||
Debug("APF: Send keepalive reply");
|
||||
}
|
||||
|
||||
function ProcessData(socket) {
|
||||
|
@ -246,7 +242,7 @@ function CreateAPFClient(parent, args) {
|
|||
switch (cmd) {
|
||||
case APFProtocol.SERVICE_ACCEPT: {
|
||||
var slen = ReadInt(data, 1), service = data.substring(5, 6 + slen);
|
||||
//Debug("APF: Service request to " + service + " accepted.");
|
||||
Debug("APF: Service request to " + service + " accepted.");
|
||||
if (service == 'auth@amt.intel.com') {
|
||||
if (obj.cirastate >= CIRASTATE.AUTH_SERVICE_REQUEST_SENT) {
|
||||
SendUserAuthRequest(socket.ws, obj.args.mpsuser, obj.args.mpspass);
|
||||
|
@ -261,47 +257,47 @@ function CreateAPFClient(parent, args) {
|
|||
case APFProtocol.REQUEST_SUCCESS: {
|
||||
if (len >= 5) {
|
||||
var port = ReadInt(data, 1);
|
||||
//Debug("APF: Request to port forward " + port + " successful.");
|
||||
Debug("APF: Request to port forward " + port + " successful.");
|
||||
// iterate to pending port forward request
|
||||
if (obj.pfwd_idx < pfwd_ports.length) {
|
||||
SendGlobalRequestPfwd(socket.ws, obj.args.clientname, pfwd_ports[obj.pfwd_idx++]);
|
||||
} else {
|
||||
// no more port forward, now setup timer to send keep alive
|
||||
//Debug("APF: Start keep alive for every " + obj.args.mpskeepalive + " ms.");
|
||||
Debug("APF: Start keep alive for every " + obj.args.mpskeepalive + " ms.");
|
||||
obj.timer = setInterval(function () {
|
||||
SendKeepAliveRequest(obj.forwardClient.ws);
|
||||
}, obj.args.mpskeepalive);//
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
//Debug("APF: Request successful.");
|
||||
Debug("APF: Request successful.");
|
||||
return 1;
|
||||
}
|
||||
case APFProtocol.USERAUTH_SUCCESS: {
|
||||
//Debug("APF: User Authentication successful");
|
||||
Debug("APF: User Authentication successful");
|
||||
// Send Pfwd service request
|
||||
SendServiceRequest(socket.ws, 'pfwd@amt.intel.com');
|
||||
return 1;
|
||||
}
|
||||
case APFProtocol.USERAUTH_FAILURE: {
|
||||
//Debug("APF: User Authentication failed");
|
||||
Debug("APF: User Authentication failed");
|
||||
obj.cirastate = CIRASTATE.FAILED;
|
||||
return 14;
|
||||
}
|
||||
case APFProtocol.KEEPALIVE_REQUEST: {
|
||||
//Debug("APF: Keep Alive Request with cookie: " + ReadInt(data, 1));
|
||||
Debug("APF: Keep Alive Request with cookie: " + ReadInt(data, 1));
|
||||
SendKeepAliveReply(socket.ws, ReadInt(data, 1));
|
||||
return 5;
|
||||
}
|
||||
case APFProtocol.KEEPALIVE_REPLY: {
|
||||
//Debug("APF: Keep Alive Reply with cookie: " + ReadInt(data, 1));
|
||||
Debug("APF: Keep Alive Reply with cookie: " + ReadInt(data, 1));
|
||||
return 5;
|
||||
}
|
||||
// Channel management
|
||||
case APFProtocol.CHANNEL_OPEN: {
|
||||
// Parse CHANNEL OPEN request
|
||||
var p_res = parseChannelOpen(data);
|
||||
//Debug("APF: CHANNEL_OPEN request: " + JSON.stringify(p_res));
|
||||
Debug("APF: CHANNEL_OPEN request: " + JSON.stringify(p_res));
|
||||
// Check if target port is in pfwd_ports
|
||||
if (pfwd_ports.indexOf(p_res.target_port) >= 0) {
|
||||
// Connect socket to that port
|
||||
|
@ -322,21 +318,15 @@ function CreateAPFClient(parent, args) {
|
|||
});
|
||||
|
||||
chan.on('error', function (e) {
|
||||
//Debug("Downlink connection error: " + e);
|
||||
Debug("Downlink connection error: " + e);
|
||||
});
|
||||
|
||||
chan.on('end', function () {
|
||||
var chan = obj.downlinks[p_res.sender_chan];
|
||||
if (chan != null) {
|
||||
try {
|
||||
//Debug("Socket ends.");
|
||||
SendChannelClose(socket.ws, p_res.sender_chan);
|
||||
chan.xclosed = 1;
|
||||
// Add some delay before removing... otherwise race condition
|
||||
setTimeout(function () { delete obj.downlinks[p_res.sender_chan]; }, 100);
|
||||
} catch (e) {
|
||||
//Debug("Downlink connection exception: " + e);
|
||||
}
|
||||
Debug("Socket ends.");
|
||||
try { SendChannelClose(socket.ws, p_res.sender_chan); } catch (ex) { }
|
||||
delete obj.downlinks[p_res.sender_chan];
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -348,22 +338,17 @@ function CreateAPFClient(parent, args) {
|
|||
return p_res.len;
|
||||
}
|
||||
case APFProtocol.CHANNEL_OPEN_CONFIRMATION: {
|
||||
//Debug("APF: CHANNEL_OPEN_CONFIRMATION");
|
||||
Debug("APF: CHANNEL_OPEN_CONFIRMATION");
|
||||
return 17;
|
||||
}
|
||||
case APFProtocol.CHANNEL_CLOSE: {
|
||||
var rcpt_chan = ReadInt(data, 1);
|
||||
//Debug("APF: CHANNEL_CLOSE: " + rcpt_chan);
|
||||
var chan = obj.downlinks[rcpt_chan];
|
||||
if ((chan != null) && (chan.xclosed !== 1)) {
|
||||
SendChannelClose(socket.ws, rcpt_chan);
|
||||
try { obj.downlinks[rcpt_chan].end(); } catch (e) { }
|
||||
delete obj.downlinks[rcpt_chan];
|
||||
}
|
||||
Debug("APF: CHANNEL_CLOSE: " + rcpt_chan);
|
||||
try { obj.downlinks[rcpt_chan].end(); } catch (ex) { }
|
||||
return 5;
|
||||
}
|
||||
case APFProtocol.CHANNEL_DATA: {
|
||||
//Debug("APF: CHANNEL_DATA: " + JSON.stringify(rstr2hex(data)));
|
||||
Debug("APF: CHANNEL_DATA: " + JSON.stringify(rstr2hex(data)));
|
||||
var rcpt_chan = ReadInt(data, 1);
|
||||
var chan_data_len = ReadInt(data, 5);
|
||||
var chan_data = data.substring(9, 9 + chan_data_len);
|
||||
|
@ -372,22 +357,26 @@ function CreateAPFClient(parent, args) {
|
|||
chan.curInWindow += chan_data_len;
|
||||
try {
|
||||
chan.write(Buffer.from(chan_data, 'binary'), function () {
|
||||
//Debug("Write completed.");
|
||||
Debug("Write completed.");
|
||||
// If the incoming window is over half used, send an adjust.
|
||||
if (this.curInWindow > (this.maxInWindow / 2)) { SendChannelWindowAdjust(socket.ws, rcpt_chan, this.curInWindow); this.curInWindow = 0; }
|
||||
});
|
||||
} catch (e) {
|
||||
//Debug("Cannot forward data to downlink socket.");
|
||||
}
|
||||
} catch (ex) { Debug("Cannot forward data to downlink socket."); }
|
||||
}
|
||||
return 9 + chan_data_len;
|
||||
}
|
||||
case APFProtocol.CHANNEL_WINDOW_ADJUST: {
|
||||
//Debug("APF: CHANNEL_WINDOW_ADJUST ");
|
||||
Debug("APF: CHANNEL_WINDOW_ADJUST");
|
||||
return 9;
|
||||
}
|
||||
case APFProtocol.JSON_CONTROL: {
|
||||
Debug("APF: JSON_CONTROL");
|
||||
var len = ReadInt(data, 1);
|
||||
if (obj.onJsonControl) { var o = null; try { o = JSON.parse(data.substring(5, 5 + len)); } catch (ex) { } if (o != null) { obj.onJsonControl(o); } }
|
||||
return 5 + len;
|
||||
}
|
||||
default: {
|
||||
//Debug("CMD: " + cmd + " is not implemented.");
|
||||
Debug("CMD: " + cmd + " is not implemented.");
|
||||
obj.cirastate = CIRASTATE.FAILED;
|
||||
return 0;
|
||||
}
|
||||
|
@ -412,36 +401,32 @@ function CreateAPFClient(parent, args) {
|
|||
|
||||
function SendChannelOpenFailure(socket, chan_data) {
|
||||
socket.write(String.fromCharCode(APFProtocol.CHANNEL_OPEN_FAILURE) + IntToStr(chan_data.sender_chan) + IntToStr(2) + IntToStr(0) + IntToStr(0));
|
||||
//Debug("APF: Send ChannelOpenFailure");
|
||||
Debug("APF: Send ChannelOpenFailure");
|
||||
}
|
||||
|
||||
function SendChannelOpenConfirm(socket, chan_data) {
|
||||
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));
|
||||
//Debug("APF: Send ChannelOpenConfirmation");
|
||||
Debug("APF: Send ChannelOpenConfirmation");
|
||||
}
|
||||
|
||||
function SendChannelWindowAdjust(socket, chan, size) {
|
||||
socket.write(String.fromCharCode(APFProtocol.CHANNEL_WINDOW_ADJUST) + IntToStr(chan) + IntToStr(size));
|
||||
//Debug("APF: Send ChannelWindowAdjust: " + rstr2hex(data));
|
||||
Debug("APF: Send ChannelWindowAdjust, channel: " + chan + ", size: " + size);
|
||||
}
|
||||
|
||||
function SendChannelData(socket, chan, data) {
|
||||
socket.write(Buffer.concat([Buffer.from(String.fromCharCode(APFProtocol.CHANNEL_DATA) + IntToStr(chan) + IntToStr(data.length), 'binary'), data]));
|
||||
//Debug("APF: Send ChannelData: " + rstr2hex(buf));
|
||||
Debug("APF: Send ChannelData: " + data.toString('hex'));
|
||||
}
|
||||
|
||||
function SendChannelClose(socket, chan) {
|
||||
socket.write(String.fromCharCode(APFProtocol.CHANNEL_CLOSE) + IntToStr(chan));
|
||||
//Debug("APF: Send ChannelClose ");
|
||||
Debug("APF: Send ChannelClose ");
|
||||
}
|
||||
|
||||
obj.connect = function () {
|
||||
if (obj.forwardClient != null) {
|
||||
try {
|
||||
obj.forwardClient.ws.end();
|
||||
} catch (e) {
|
||||
Debug(e);
|
||||
}
|
||||
try { obj.forwardClient.ws.end(); } catch (ex) { Debug(ex); }
|
||||
//obj.forwardClient = null;
|
||||
}
|
||||
obj.cirastate = CIRASTATE.INITIAL;
|
||||
|
@ -457,7 +442,7 @@ function CreateAPFClient(parent, args) {
|
|||
obj.forwardClient.end(); // end request, trigger completion of HTTP request
|
||||
}
|
||||
|
||||
obj.disconnect = function () { try { obj.forwardClient.ws.end(); } catch (e) { Debug(e); } }
|
||||
obj.disconnect = function () { try { obj.forwardClient.ws.end(); } catch (ex) { Debug(ex); } }
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue