mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-03-09 15:40:18 +00:00
Merged APF and MPS servers, improved APF client.
This commit is contained in:
parent
3ff007c8d8
commit
bc4e07b5fe
8 changed files with 495 additions and 1242 deletions
|
@ -6,60 +6,30 @@
|
|||
* @version v0.0.1
|
||||
*/
|
||||
|
||||
function CreateAPFClient(parent, args) {
|
||||
function CreateAPFClient(parent, args) {
|
||||
var obj = {};
|
||||
obj.parent = parent;
|
||||
obj.args = args;
|
||||
obj.http = require('http');
|
||||
//obj.common = require('common');
|
||||
obj.net = require('net');
|
||||
obj.net = require('net');
|
||||
obj.forwardClient = null;
|
||||
obj.downlinks = {};
|
||||
obj.pfwd_idx = 0;
|
||||
// keep alive timer
|
||||
obj.timer = null;
|
||||
|
||||
// some 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);
|
||||
};
|
||||
obj.timer = null; // Keep alive timer
|
||||
|
||||
function hex2rstr(d) {
|
||||
var r = '', m = ('' + d).match(/../g), t;
|
||||
while (t = m.shift()) { r += String.fromCharCode('0x' + t); }
|
||||
return r;
|
||||
};
|
||||
// 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; }
|
||||
|
||||
// Convert decimal to hex
|
||||
function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); };
|
||||
|
||||
// Convert a raw string to a hex string
|
||||
function rstr2hex(input) {
|
||||
var r = '', i;
|
||||
for (i = 0; i < input.length; i++) { r += char2hex(input.charCodeAt(i)); }
|
||||
return r;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
// CIRA state
|
||||
var CIRASTATE = {
|
||||
INITIAL: 0,
|
||||
|
@ -85,9 +55,10 @@ function CreateAPFClient(parent, args) {
|
|||
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 ];
|
||||
|
||||
// AMT forwarded port list for non-TLS mode
|
||||
var pfwd_ports = [16992, 623, 16994, 5900];
|
||||
// protocol definitions
|
||||
var APFProtocol = {
|
||||
UNKNOWN: 0,
|
||||
|
@ -152,7 +123,7 @@ function CreateAPFClient(parent, args) {
|
|||
Debug("APF Secure WebSocket connected.");
|
||||
//console.log(JSON.stringify(resp));
|
||||
obj.forwardClient.tag = { accumulator: [] };
|
||||
obj.forwardClient.ws = ws;
|
||||
obj.forwardClient.ws = ws;
|
||||
obj.forwardClient.ws.on('end', function () {
|
||||
Debug("APF: Connection is closing.");
|
||||
if (obj.timer != null) {
|
||||
|
@ -162,12 +133,12 @@ function CreateAPFClient(parent, args) {
|
|||
});
|
||||
|
||||
obj.forwardClient.ws.on('data', function (data) {
|
||||
obj.forwardClient.tag.accumulator += hex2rstr(buf2hex(data));
|
||||
obj.forwardClient.tag.accumulator += hex2rstr(buf2hex(data));
|
||||
try {
|
||||
var len = 0;
|
||||
do {
|
||||
len = ProcessData(obj.forwardClient);
|
||||
if (len > 0) {
|
||||
if (len > 0) {
|
||||
obj.forwardClient.tag.accumulator = obj.forwardClient.tag.accumulator.slice(len);
|
||||
}
|
||||
if (obj.cirastate == CIRASTATE.FAILED) {
|
||||
|
@ -178,44 +149,26 @@ function CreateAPFClient(parent, args) {
|
|||
} catch (e) {
|
||||
Debug(e);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
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;
|
||||
SendProtocolVersion(obj.forwardClient.ws, obj.args.clientuuid);
|
||||
SendServiceRequest(obj.forwardClient.ws, 'auth@amt.intel.com');
|
||||
}
|
||||
|
||||
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);
|
||||
ret += 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function SendProtocolVersion(socket, uuid) {
|
||||
function SendProtocolVersion(socket, uuid) {
|
||||
var buuid = strToGuid(uuid);
|
||||
var data = String.fromCharCode(APFProtocol.PROTOCOLVERSION) + '' + IntToStr(1) + IntToStr(0) + IntToStr(0) + hex2rstr(buuid) + binzerostring(64);
|
||||
socket.write(data);
|
||||
Debug("APF: Send protocol version 1 0 " + uuid);
|
||||
socket.write(data);
|
||||
Debug("APF: Send protocol version 1 0 " + uuid);
|
||||
obj.cirastate = CIRASTATE.PROTOCOL_VERSION_SENT;
|
||||
}
|
||||
|
||||
|
@ -267,7 +220,8 @@ function CreateAPFClient(parent, args) {
|
|||
var len = socket.tag.accumulator.length;
|
||||
var data = socket.tag.accumulator;
|
||||
if (len == 0) { return 0; }
|
||||
// respond to MPS according to obj.cirastate
|
||||
|
||||
// Respond to MPS according to obj.cirastate
|
||||
switch (cmd) {
|
||||
case APFProtocol.SERVICE_ACCEPT: {
|
||||
var slen = ReadInt(data, 1);
|
||||
|
@ -325,39 +279,50 @@ function CreateAPFClient(parent, args) {
|
|||
}
|
||||
// Channel management
|
||||
case APFProtocol.CHANNEL_OPEN: {
|
||||
//parse CHANNEL OPEN request
|
||||
// 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
|
||||
obj.downlinks[p_res.sender_chan] = obj.net.createConnection({ host: obj.args.clientaddress, port: p_res.target_port }, function () {
|
||||
//obj.downlinks[p_res.sender_chan].setEncoding('binary');//assume everything is binary, not interpreting
|
||||
// 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);
|
||||
});
|
||||
|
||||
obj.downlinks[p_res.sender_chan].on('data', function (ddata) {
|
||||
//Relay data to fordwardclient
|
||||
// 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.length, ddata);
|
||||
});
|
||||
|
||||
obj.downlinks[p_res.sender_chan].on('error', function (e) {
|
||||
chan.on('error', function (e) {
|
||||
Debug("Downlink connection error: " + e);
|
||||
});
|
||||
|
||||
obj.downlinks[p_res.sender_chan].on('end', function () {
|
||||
if (obj.downlinks[p_res.sender_chan]) {
|
||||
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);
|
||||
// add some delay before removing... otherwise race condition
|
||||
setTimeout(function () { delete obj.downlinks[p_res.sender_chan];},100);
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
obj.downlinks[p_res.sender_chan] = chan;
|
||||
} else {
|
||||
// Not a supported port, fail the connection
|
||||
SendChannelOpenFailure(socket.ws, p_res);
|
||||
}
|
||||
return p_res.len;
|
||||
|
@ -369,11 +334,12 @@ function CreateAPFClient(parent, args) {
|
|||
case APFProtocol.CHANNEL_CLOSE: {
|
||||
var rcpt_chan = ReadInt(data, 1);
|
||||
Debug("APF: CHANNEL_CLOSE: " + rcpt_chan);
|
||||
SendChannelClose(socket.ws, rcpt_chan);
|
||||
try {
|
||||
obj.downlinks[rcpt_chan].end();
|
||||
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];
|
||||
} catch (e) { }
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
case APFProtocol.CHANNEL_DATA: {
|
||||
|
@ -381,11 +347,14 @@ function CreateAPFClient(parent, args) {
|
|||
var rcpt_chan = ReadInt(data, 1);
|
||||
var chan_data_len = ReadInt(data, 5);
|
||||
var chan_data = data.substring(9, 9 + chan_data_len);
|
||||
if (obj.downlinks[rcpt_chan]) {
|
||||
var chan = obj.downlinks[rcpt_chan];
|
||||
if (chan != null) {
|
||||
chan.curInWindow += chan_data_len;
|
||||
try {
|
||||
obj.downlinks[rcpt_chan].write(chan_data, 'binary', function () {
|
||||
chan.write(chan_data, 'binary', function () {
|
||||
Debug("Write completed.");
|
||||
SendChannelWindowAdjust(socket.ws, rcpt_chan, chan_data_len);//I have full window capacity now
|
||||
// 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.");
|
||||
|
@ -406,17 +375,7 @@ function CreateAPFClient(parent, args) {
|
|||
}
|
||||
|
||||
function parseChannelOpen(data) {
|
||||
var result = {
|
||||
len: 0, //to be filled later
|
||||
cmd: APFProtocol.CHANNEL_OPEN,
|
||||
chan_type: "", //to be filled later
|
||||
sender_chan: 0, //to be filled later
|
||||
window_size: 0, //to be filled later
|
||||
target_address: "", //to be filled later
|
||||
target_port: 0, //to be filled later
|
||||
origin_address: "", //to be filled later
|
||||
origin_port: 0, //to be filled later
|
||||
};
|
||||
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);
|
||||
|
@ -430,12 +389,14 @@ function CreateAPFClient(parent, args) {
|
|||
result.len = 33 + chan_type_slen + c_len + o_len;
|
||||
return result;
|
||||
}
|
||||
|
||||
function SendChannelOpenFailure(socket, chan_data) {
|
||||
var data = String.fromCharCode(APFProtocol.CHANNEL_OPEN_FAILURE) + IntToStr(chan_data.sender_chan)
|
||||
+ IntToStr(2) + IntToStr(0) + IntToStr(0);
|
||||
socket.write(data);
|
||||
Debug("APF: Send ChannelOpenFailure");
|
||||
}
|
||||
|
||||
function SendChannelOpenConfirm(socket, chan_data) {
|
||||
var data = String.fromCharCode(APFProtocol.CHANNEL_OPEN_CONFIRMATION) + IntToStr(chan_data.sender_chan)
|
||||
+ IntToStr(chan_data.sender_chan) + IntToStr(chan_data.window_size) + IntToStr(0xFFFFFFFF);
|
||||
|
@ -472,25 +433,18 @@ function CreateAPFClient(parent, args) {
|
|||
}
|
||||
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);
|
||||
var wsoptions = obj.http.parseUri(obj.args.mpsurl);
|
||||
wsoptions.rejectUnauthorized = 0;
|
||||
obj.forwardClient = obj.http.request(wsoptions);
|
||||
obj.forwardClient.upgrade = obj.onSecureConnect;
|
||||
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 (e) {
|
||||
Debug(e);
|
||||
}
|
||||
}
|
||||
obj.disconnect = function () { try { obj.forwardClient.ws.end(); } catch (e) { Debug(e); } }
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue