Added TLS support to APF tunnels.
This commit is contained in:
parent
dcca252f96
commit
2965e7b23a
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
/**
|
/**
|
||||||
* @description APF/CIRA Client for Duktape
|
* @description APF/CIRA Client for Duktape
|
||||||
* @author Joko Sastriawan & Ylian Saint-Hilaire
|
* @author Joko Sastriawan & Ylian Saint-Hilaire
|
||||||
* @copyright Intel Corporation 2019
|
* @copyright Intel Corporation 2020
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
* @version v0.0.2
|
* @version v0.0.2
|
||||||
*/
|
*/
|
||||||
|
@ -139,12 +139,12 @@ function CreateAPFClient(parent, args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.onSecureConnect = function onSecureConnect(resp, ws, head) {
|
obj.onSecureConnect = function onSecureConnect(resp, ws, head) {
|
||||||
Debug("APF Secure WebSocket connected.");
|
//Debug("APF Secure WebSocket connected.");
|
||||||
//console.log(JSON.stringify(resp));
|
//console.log(JSON.stringify(resp));
|
||||||
obj.forwardClient.tag = { accumulator: [] };
|
obj.forwardClient.tag = { accumulator: [] };
|
||||||
obj.forwardClient.ws = ws;
|
obj.forwardClient.ws = ws;
|
||||||
obj.forwardClient.ws.on('end', function () {
|
obj.forwardClient.ws.on('end', function () {
|
||||||
Debug("APF: Connection is closing.");
|
//Debug("APF: Connection is closing.");
|
||||||
if (obj.timer != null) {
|
if (obj.timer != null) {
|
||||||
clearInterval(obj.timer);
|
clearInterval(obj.timer);
|
||||||
obj.timer = null;
|
obj.timer = null;
|
||||||
|
@ -157,11 +157,9 @@ function CreateAPFClient(parent, args) {
|
||||||
var len = 0;
|
var len = 0;
|
||||||
do {
|
do {
|
||||||
len = ProcessData(obj.forwardClient);
|
len = ProcessData(obj.forwardClient);
|
||||||
if (len > 0) {
|
if (len > 0) { obj.forwardClient.tag.accumulator = obj.forwardClient.tag.accumulator.slice(len); }
|
||||||
obj.forwardClient.tag.accumulator = obj.forwardClient.tag.accumulator.slice(len);
|
|
||||||
}
|
|
||||||
if (obj.cirastate == CIRASTATE.FAILED) {
|
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();
|
obj.forwardClient.ws.end();
|
||||||
}
|
}
|
||||||
} while (len > 0);
|
} while (len > 0);
|
||||||
|
@ -171,7 +169,7 @@ function CreateAPFClient(parent, args) {
|
||||||
});
|
});
|
||||||
|
|
||||||
obj.forwardClient.ws.on('error', function (e) {
|
obj.forwardClient.ws.on('error', function (e) {
|
||||||
Debug("APF: Connection error, ending connecting.");
|
//Debug("APF: Connection error, ending connecting.");
|
||||||
if (obj.timer != null) {
|
if (obj.timer != null) {
|
||||||
clearInterval(obj.timer);
|
clearInterval(obj.timer);
|
||||||
obj.timer = null;
|
obj.timer = null;
|
||||||
|
@ -187,20 +185,20 @@ function CreateAPFClient(parent, args) {
|
||||||
function SendJsonControl(socket, o) {
|
function SendJsonControl(socket, o) {
|
||||||
var data = JSON.stringify(o)
|
var data = JSON.stringify(o)
|
||||||
socket.write(String.fromCharCode(APFProtocol.JSON_CONTROL) + IntToStr(data.length) + data);
|
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) {
|
function SendProtocolVersion(socket, uuid) {
|
||||||
var data = String.fromCharCode(APFProtocol.PROTOCOLVERSION) + IntToStr(1) + IntToStr(0) + IntToStr(0) + hex2rstr(strToGuid(uuid)) + binzerostring(64);
|
var data = String.fromCharCode(APFProtocol.PROTOCOLVERSION) + IntToStr(1) + IntToStr(0) + IntToStr(0) + hex2rstr(strToGuid(uuid)) + binzerostring(64);
|
||||||
socket.write(data);
|
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;
|
obj.cirastate = CIRASTATE.PROTOCOL_VERSION_SENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SendServiceRequest(socket, service) {
|
function SendServiceRequest(socket, service) {
|
||||||
var data = String.fromCharCode(APFProtocol.SERVICE_REQUEST) + IntToStr(service.length) + service;
|
var data = String.fromCharCode(APFProtocol.SERVICE_REQUEST) + IntToStr(service.length) + service;
|
||||||
socket.write(data);
|
socket.write(data);
|
||||||
Debug("APF: Send service request " + service);
|
//Debug("APF: Send service request " + service);
|
||||||
if (service == 'auth@amt.intel.com') {
|
if (service == 'auth@amt.intel.com') {
|
||||||
obj.cirastate = CIRASTATE.AUTH_SERVICE_REQUEST_SENT;
|
obj.cirastate = CIRASTATE.AUTH_SERVICE_REQUEST_SENT;
|
||||||
} else if (service == 'pfwd@amt.intel.com') {
|
} else if (service == 'pfwd@amt.intel.com') {
|
||||||
|
@ -215,7 +213,7 @@ function CreateAPFClient(parent, args) {
|
||||||
data += IntToStr(8) + 'password';
|
data += IntToStr(8) + 'password';
|
||||||
data += binzerostring(1) + IntToStr(pass.length) + pass;
|
data += binzerostring(1) + IntToStr(pass.length) + pass;
|
||||||
socket.write(data);
|
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;
|
obj.cirastate = CIRASTATE.AUTH_REQUEST_SENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,20 +222,18 @@ function CreateAPFClient(parent, args) {
|
||||||
var data = String.fromCharCode(APFProtocol.GLOBAL_REQUEST) + IntToStr(tcpipfwd.length) + tcpipfwd + binzerostring(1, 1);
|
var data = String.fromCharCode(APFProtocol.GLOBAL_REQUEST) + IntToStr(tcpipfwd.length) + tcpipfwd + binzerostring(1, 1);
|
||||||
data += IntToStr(amthostname.length) + amthostname + IntToStr(amtport);
|
data += IntToStr(amthostname.length) + amthostname + IntToStr(amtport);
|
||||||
socket.write(data);
|
socket.write(data);
|
||||||
Debug("APF: Send tcpip-forward " + amthostname + ":" + amtport);
|
//Debug("APF: Send tcpip-forward " + amthostname + ":" + amtport);
|
||||||
obj.cirastate = CIRASTATE.GLOBAL_REQUEST_SENT;
|
obj.cirastate = CIRASTATE.GLOBAL_REQUEST_SENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SendKeepAliveRequest(socket) {
|
function SendKeepAliveRequest(socket) {
|
||||||
var data = String.fromCharCode(APFProtocol.KEEPALIVE_REQUEST) + IntToStr(255);
|
socket.write(String.fromCharCode(APFProtocol.KEEPALIVE_REQUEST) + IntToStr(255));
|
||||||
socket.write(data);
|
//Debug("APF: Send keepalive request");
|
||||||
Debug("APF: Send keepalive request");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function SendKeepAliveReply(socket, cookie) {
|
function SendKeepAliveReply(socket, cookie) {
|
||||||
var data = String.fromCharCode(APFProtocol.KEEPALIVE_REPLY) + IntToStr(cookie);
|
socket.write(String.fromCharCode(APFProtocol.KEEPALIVE_REPLY) + IntToStr(cookie));
|
||||||
socket.write(data);
|
//Debug("APF: Send keepalive reply");
|
||||||
Debug("APF: Send keepalive reply");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function ProcessData(socket) {
|
function ProcessData(socket) {
|
||||||
|
@ -249,9 +245,8 @@ function CreateAPFClient(parent, args) {
|
||||||
// Respond to MPS according to obj.cirastate
|
// Respond to MPS according to obj.cirastate
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case APFProtocol.SERVICE_ACCEPT: {
|
case APFProtocol.SERVICE_ACCEPT: {
|
||||||
var slen = ReadInt(data, 1);
|
var slen = ReadInt(data, 1), service = data.substring(5, 6 + slen);
|
||||||
var 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 (service == 'auth@amt.intel.com') {
|
||||||
if (obj.cirastate >= CIRASTATE.AUTH_SERVICE_REQUEST_SENT) {
|
if (obj.cirastate >= CIRASTATE.AUTH_SERVICE_REQUEST_SENT) {
|
||||||
SendUserAuthRequest(socket.ws, obj.args.mpsuser, obj.args.mpspass);
|
SendUserAuthRequest(socket.ws, obj.args.mpsuser, obj.args.mpspass);
|
||||||
|
@ -266,47 +261,47 @@ function CreateAPFClient(parent, args) {
|
||||||
case APFProtocol.REQUEST_SUCCESS: {
|
case APFProtocol.REQUEST_SUCCESS: {
|
||||||
if (len >= 5) {
|
if (len >= 5) {
|
||||||
var port = ReadInt(data, 1);
|
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
|
// iterate to pending port forward request
|
||||||
if (obj.pfwd_idx < pfwd_ports.length) {
|
if (obj.pfwd_idx < pfwd_ports.length) {
|
||||||
SendGlobalRequestPfwd(socket.ws, obj.args.clientname, pfwd_ports[obj.pfwd_idx++]);
|
SendGlobalRequestPfwd(socket.ws, obj.args.clientname, pfwd_ports[obj.pfwd_idx++]);
|
||||||
} else {
|
} else {
|
||||||
// no more port forward, now setup timer to send keep alive
|
// 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 () {
|
obj.timer = setInterval(function () {
|
||||||
SendKeepAliveRequest(obj.forwardClient.ws);
|
SendKeepAliveRequest(obj.forwardClient.ws);
|
||||||
}, obj.args.mpskeepalive);//
|
}, obj.args.mpskeepalive);//
|
||||||
}
|
}
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
Debug("APF: Request successful.");
|
//Debug("APF: Request successful.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
case APFProtocol.USERAUTH_SUCCESS: {
|
case APFProtocol.USERAUTH_SUCCESS: {
|
||||||
Debug("APF: User Authentication successful");
|
//Debug("APF: User Authentication successful");
|
||||||
// Send Pfwd service request
|
// Send Pfwd service request
|
||||||
SendServiceRequest(socket.ws, 'pfwd@amt.intel.com');
|
SendServiceRequest(socket.ws, 'pfwd@amt.intel.com');
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
case APFProtocol.USERAUTH_FAILURE: {
|
case APFProtocol.USERAUTH_FAILURE: {
|
||||||
Debug("APF: User Authentication failed");
|
//Debug("APF: User Authentication failed");
|
||||||
obj.cirastate = CIRASTATE.FAILED;
|
obj.cirastate = CIRASTATE.FAILED;
|
||||||
return 14;
|
return 14;
|
||||||
}
|
}
|
||||||
case APFProtocol.KEEPALIVE_REQUEST: {
|
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));
|
SendKeepAliveReply(socket.ws, ReadInt(data, 1));
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
case APFProtocol.KEEPALIVE_REPLY: {
|
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;
|
return 5;
|
||||||
}
|
}
|
||||||
// Channel management
|
// Channel management
|
||||||
case APFProtocol.CHANNEL_OPEN: {
|
case APFProtocol.CHANNEL_OPEN: {
|
||||||
// Parse CHANNEL OPEN request
|
// Parse CHANNEL OPEN request
|
||||||
var p_res = parseChannelOpen(data);
|
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
|
// Check if target port is in pfwd_ports
|
||||||
if (pfwd_ports.indexOf(p_res.target_port) >= 0) {
|
if (pfwd_ports.indexOf(p_res.target_port) >= 0) {
|
||||||
// Connect socket to that port
|
// Connect socket to that port
|
||||||
|
@ -323,24 +318,24 @@ function CreateAPFClient(parent, args) {
|
||||||
chan.on('data', function (ddata) {
|
chan.on('data', function (ddata) {
|
||||||
// Relay data to fordwardclient
|
// Relay data to fordwardclient
|
||||||
// TODO: Implement flow control
|
// TODO: Implement flow control
|
||||||
SendChannelData(socket.ws, p_res.sender_chan, ddata.length, ddata);
|
SendChannelData(socket.ws, p_res.sender_chan, ddata);
|
||||||
});
|
});
|
||||||
|
|
||||||
chan.on('error', function (e) {
|
chan.on('error', function (e) {
|
||||||
Debug("Downlink connection error: " + e);
|
//Debug("Downlink connection error: " + e);
|
||||||
});
|
});
|
||||||
|
|
||||||
chan.on('end', function () {
|
chan.on('end', function () {
|
||||||
var chan = obj.downlinks[p_res.sender_chan];
|
var chan = obj.downlinks[p_res.sender_chan];
|
||||||
if (chan != null) {
|
if (chan != null) {
|
||||||
try {
|
try {
|
||||||
Debug("Socket ends.");
|
//Debug("Socket ends.");
|
||||||
SendChannelClose(socket.ws, p_res.sender_chan);
|
SendChannelClose(socket.ws, p_res.sender_chan);
|
||||||
chan.xclosed = 1;
|
chan.xclosed = 1;
|
||||||
// Add some delay before removing... otherwise race condition
|
// Add some delay before removing... otherwise race condition
|
||||||
setTimeout(function () { delete obj.downlinks[p_res.sender_chan]; }, 100);
|
setTimeout(function () { delete obj.downlinks[p_res.sender_chan]; }, 100);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Debug("Downlink connection exception: " + e);
|
//Debug("Downlink connection exception: " + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -353,12 +348,12 @@ function CreateAPFClient(parent, args) {
|
||||||
return p_res.len;
|
return p_res.len;
|
||||||
}
|
}
|
||||||
case APFProtocol.CHANNEL_OPEN_CONFIRMATION: {
|
case APFProtocol.CHANNEL_OPEN_CONFIRMATION: {
|
||||||
Debug("APF: CHANNEL_OPEN_CONFIRMATION");
|
//Debug("APF: CHANNEL_OPEN_CONFIRMATION");
|
||||||
return 17;
|
return 17;
|
||||||
}
|
}
|
||||||
case APFProtocol.CHANNEL_CLOSE: {
|
case APFProtocol.CHANNEL_CLOSE: {
|
||||||
var rcpt_chan = ReadInt(data, 1);
|
var rcpt_chan = ReadInt(data, 1);
|
||||||
Debug("APF: CHANNEL_CLOSE: " + rcpt_chan);
|
//Debug("APF: CHANNEL_CLOSE: " + rcpt_chan);
|
||||||
var chan = obj.downlinks[rcpt_chan];
|
var chan = obj.downlinks[rcpt_chan];
|
||||||
if ((chan != null) && (chan.xclosed !== 1)) {
|
if ((chan != null) && (chan.xclosed !== 1)) {
|
||||||
SendChannelClose(socket.ws, rcpt_chan);
|
SendChannelClose(socket.ws, rcpt_chan);
|
||||||
|
@ -368,7 +363,7 @@ function CreateAPFClient(parent, args) {
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
case APFProtocol.CHANNEL_DATA: {
|
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 rcpt_chan = ReadInt(data, 1);
|
||||||
var chan_data_len = ReadInt(data, 5);
|
var chan_data_len = ReadInt(data, 5);
|
||||||
var chan_data = data.substring(9, 9 + chan_data_len);
|
var chan_data = data.substring(9, 9 + chan_data_len);
|
||||||
|
@ -376,23 +371,23 @@ function CreateAPFClient(parent, args) {
|
||||||
if (chan != null) {
|
if (chan != null) {
|
||||||
chan.curInWindow += chan_data_len;
|
chan.curInWindow += chan_data_len;
|
||||||
try {
|
try {
|
||||||
chan.write(chan_data, 'binary', function () {
|
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 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; }
|
if (this.curInWindow > (this.maxInWindow / 2)) { SendChannelWindowAdjust(socket.ws, rcpt_chan, this.curInWindow); this.curInWindow = 0; }
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Debug("Cannot forward data to downlink socket.");
|
//Debug("Cannot forward data to downlink socket.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 9 + chan_data_len;
|
return 9 + chan_data_len;
|
||||||
}
|
}
|
||||||
case APFProtocol.CHANNEL_WINDOW_ADJUST: {
|
case APFProtocol.CHANNEL_WINDOW_ADJUST: {
|
||||||
Debug("APF: CHANNEL_WINDOW_ADJUST ");
|
//Debug("APF: CHANNEL_WINDOW_ADJUST ");
|
||||||
return 9;
|
return 9;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
Debug("CMD: " + cmd + " is not implemented.");
|
//Debug("CMD: " + cmd + " is not implemented.");
|
||||||
obj.cirastate = CIRASTATE.FAILED;
|
obj.cirastate = CIRASTATE.FAILED;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -416,35 +411,28 @@ function CreateAPFClient(parent, args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function SendChannelOpenFailure(socket, chan_data) {
|
function SendChannelOpenFailure(socket, chan_data) {
|
||||||
var data = String.fromCharCode(APFProtocol.CHANNEL_OPEN_FAILURE) + IntToStr(chan_data.sender_chan)
|
socket.write(String.fromCharCode(APFProtocol.CHANNEL_OPEN_FAILURE) + IntToStr(chan_data.sender_chan) + IntToStr(2) + IntToStr(0) + IntToStr(0));
|
||||||
+ IntToStr(2) + IntToStr(0) + IntToStr(0);
|
//Debug("APF: Send ChannelOpenFailure");
|
||||||
socket.write(data);
|
|
||||||
Debug("APF: Send ChannelOpenFailure");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function SendChannelOpenConfirm(socket, chan_data) {
|
function SendChannelOpenConfirm(socket, chan_data) {
|
||||||
var data = String.fromCharCode(APFProtocol.CHANNEL_OPEN_CONFIRMATION) + IntToStr(chan_data.sender_chan)
|
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));
|
||||||
+ IntToStr(chan_data.sender_chan) + IntToStr(chan_data.window_size) + IntToStr(0xFFFFFFFF);
|
//Debug("APF: Send ChannelOpenConfirmation");
|
||||||
socket.write(data);
|
|
||||||
Debug("APF: Send ChannelOpenConfirmation");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function SendChannelWindowAdjust(socket, chan, size) {
|
function SendChannelWindowAdjust(socket, chan, size) {
|
||||||
var data = String.fromCharCode(APFProtocol.CHANNEL_WINDOW_ADJUST) + IntToStr(chan) + IntToStr(size);
|
socket.write(String.fromCharCode(APFProtocol.CHANNEL_WINDOW_ADJUST) + IntToStr(chan) + IntToStr(size));
|
||||||
socket.write(data);
|
//Debug("APF: Send ChannelWindowAdjust: " + rstr2hex(data));
|
||||||
Debug("APF: Send ChannelWindowAdjust: " + rstr2hex(data));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function SendChannelData(socket, chan, len, data) {
|
function SendChannelData(socket, chan, data) {
|
||||||
var buf = String.fromCharCode(APFProtocol.CHANNEL_DATA) + IntToStr(chan) + IntToStr(len) + data;
|
socket.write(Buffer.concat([Buffer.from(String.fromCharCode(APFProtocol.CHANNEL_DATA) + IntToStr(chan) + IntToStr(data.length), 'binary'), data]));
|
||||||
socket.write(buf);
|
//Debug("APF: Send ChannelData: " + rstr2hex(buf));
|
||||||
Debug("APF: Send ChannelData: " + rstr2hex(buf));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function SendChannelClose(socket, chan) {
|
function SendChannelClose(socket, chan) {
|
||||||
var buf = String.fromCharCode(APFProtocol.CHANNEL_CLOSE) + IntToStr(chan);
|
socket.write(String.fromCharCode(APFProtocol.CHANNEL_CLOSE) + IntToStr(chan));
|
||||||
socket.write(buf);
|
//Debug("APF: Send ChannelClose ");
|
||||||
Debug("APF: Send ChannelClose ");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.connect = function () {
|
obj.connect = function () {
|
||||||
|
|
|
@ -51,6 +51,16 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, ciraCon
|
||||||
// Private method
|
// Private method
|
||||||
obj.Debug = function (msg) { console.log(msg); }
|
obj.Debug = function (msg) { console.log(msg); }
|
||||||
|
|
||||||
|
// Used to add TLS to a steam
|
||||||
|
function SerialTunnel(options) {
|
||||||
|
var obj = new require('stream').Duplex(options);
|
||||||
|
obj.forwardwrite = null;
|
||||||
|
obj.updateBuffer = function (chunk) { this.push(chunk); };
|
||||||
|
obj._write = function (chunk, encoding, callback) { if (obj.forwardwrite != null) { obj.forwardwrite(chunk); } else { console.err("Failed to fwd _write."); } if (callback) callback(); }; // Pass data written to forward
|
||||||
|
obj._read = function (size) { }; // Push nothing, anything to read should be pushed from updateBuffer()
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
// Private method
|
// Private method
|
||||||
// pri = priority, if set to 1, the call is high priority and put on top of the stack.
|
// pri = priority, if set to 1, the call is high priority and put on top of the stack.
|
||||||
obj.PerformAjax = function (postdata, callback, tag, pri, url, action) {
|
obj.PerformAjax = function (postdata, callback, tag, pri, url, action) {
|
||||||
|
@ -167,11 +177,12 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, ciraCon
|
||||||
obj.kerberosDone = 0;
|
obj.kerberosDone = 0;
|
||||||
|
|
||||||
if (obj.ciraConnection != null) {
|
if (obj.ciraConnection != null) {
|
||||||
|
if (obj.xtls != 1) {
|
||||||
// Setup a new channel using the CIRA/Relay/LMS connection
|
// Setup a new channel using the CIRA/Relay/LMS connection
|
||||||
obj.socket = obj.ciraConnection.SetupChannel(obj.port);
|
obj.socket = obj.ciraConnection.SetupChannel(obj.port);
|
||||||
if (obj.socket == null) {
|
if (obj.socket == null) { obj.xxOnSocketClosed(); return; }
|
||||||
try { obj.xxOnSocketClosed(); } catch (e) { }
|
|
||||||
} else {
|
// Connect without TLS
|
||||||
obj.socket.onData = function (ccon, data) { obj.xxOnSocketData(data); }
|
obj.socket.onData = function (ccon, data) { obj.xxOnSocketData(data); }
|
||||||
obj.socket.onStateChange = function (ccon, state) {
|
obj.socket.onStateChange = function (ccon, state) {
|
||||||
if (state == 0) {
|
if (state == 0) {
|
||||||
|
@ -181,12 +192,57 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, ciraCon
|
||||||
obj.socketHeader = null;
|
obj.socketHeader = null;
|
||||||
obj.socketData = '';
|
obj.socketData = '';
|
||||||
obj.socketState = 0;
|
obj.socketState = 0;
|
||||||
try { obj.xxOnSocketClosed(); } catch (e) { }
|
obj.xxOnSocketClosed();
|
||||||
} else if (state == 2) {
|
} else if (state == 2) {
|
||||||
// Channel open success
|
// Channel open success
|
||||||
obj.xxOnSocketConnected();
|
obj.xxOnSocketConnected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Setup a new channel using the CIRA/Relay/LMS connection
|
||||||
|
obj.cirasocket = obj.ciraConnection.SetupChannel(obj.port);
|
||||||
|
if (obj.cirasocket == null) { obj.xxOnSocketClosed(); return; }
|
||||||
|
|
||||||
|
// Connect with TLS
|
||||||
|
var ser = new SerialTunnel();
|
||||||
|
|
||||||
|
// let's chain up the TLSSocket <-> SerialTunnel <-> CIRA APF (chnl)
|
||||||
|
// Anything that needs to be forwarded by SerialTunnel will be encapsulated by chnl write
|
||||||
|
ser.forwardwrite = function (msg) { obj.cirasocket.write(msg); }; // TLS ---> CIRA
|
||||||
|
|
||||||
|
// When APF tunnel return something, update SerialTunnel buffer
|
||||||
|
obj.cirasocket.onData = function (ciraconn, data) { if (data.length > 0) { try { ser.updateBuffer(Buffer.from(data, 'binary')); } catch (e) { } } }; // CIRA ---> TLS
|
||||||
|
|
||||||
|
// Handle CIRA tunnel state change
|
||||||
|
obj.cirasocket.onStateChange = function (ciraconn, state) {
|
||||||
|
if (state == 0) { obj.xxOnSocketClosed(); }
|
||||||
|
if (state == 2) {
|
||||||
|
// TLSSocket to encapsulate TLS communication, which then tunneled via SerialTunnel an then wrapped through CIRA APF
|
||||||
|
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 };
|
||||||
|
if (obj.tls1only == 1) { tlsoptions.secureProtocol = 'TLSv1_method'; }
|
||||||
|
if (obj.xtlsoptions) {
|
||||||
|
if (obj.xtlsoptions.ca) options.ca = obj.xtlsoptions.ca;
|
||||||
|
if (obj.xtlsoptions.cert) options.cert = obj.xtlsoptions.cert;
|
||||||
|
if (obj.xtlsoptions.key) options.key = obj.xtlsoptions.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
//obj.socket = new TLSSocket(ser, options);
|
||||||
|
obj.socket = obj.tls.connect(obj.port, obj.host, options, obj.xxOnSocketConnected);
|
||||||
|
obj.socket.setEncoding('binary');
|
||||||
|
obj.socket.setTimeout(6000); // Set socket idle timeout
|
||||||
|
obj.socket.on('error', function (err) { console.log("CIRA TLS Connection Error ", err); obj.xxOnSocketClosed(); });
|
||||||
|
//obj.socket.on('error', function (e) { if (e.message && e.message.indexOf('sslv3 alert bad record mac') >= 0) { obj.xtlsMethod = 1 - obj.xtlsMethod; } });
|
||||||
|
obj.socket.on('close', obj.xxOnSocketClosed);
|
||||||
|
obj.socket.on('timeout', obj.xxOnSocketTimeout);
|
||||||
|
|
||||||
|
// Decrypted tunnel from TLS communcation to be forwarded to websocket
|
||||||
|
obj.socket.on('data', function (data) { try { obj.xxOnSocketData(data.toString('binary')); } catch (e) { } }); // AMT/TLS ---> WS
|
||||||
|
|
||||||
|
// If TLS is on, forward it through TLSSocket
|
||||||
|
obj.forwardclient = obj.socket;
|
||||||
|
obj.forwardclient.xtls = 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Direct connection
|
// Direct connection
|
||||||
|
@ -229,7 +285,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, ciraCon
|
||||||
obj.xxOnSocketConnected = function () {
|
obj.xxOnSocketConnected = function () {
|
||||||
if (obj.socket == null) return;
|
if (obj.socket == null) return;
|
||||||
// check TLS certificate for webrelay and direct only
|
// check TLS certificate for webrelay and direct only
|
||||||
if ((obj.ciraConnection == null) && (obj.xtls == 1)) {
|
if (obj.xtls == 1) {
|
||||||
obj.xtlsCertificate = obj.socket.getPeerCertificate();
|
obj.xtlsCertificate = obj.socket.getPeerCertificate();
|
||||||
|
|
||||||
// ###BEGIN###{Certificates}
|
// ###BEGIN###{Certificates}
|
||||||
|
@ -365,8 +421,15 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, ciraCon
|
||||||
//obj.Debug("xxOnSocketClosed");
|
//obj.Debug("xxOnSocketClosed");
|
||||||
obj.socketState = 0;
|
obj.socketState = 0;
|
||||||
if (obj.socket != null) {
|
if (obj.socket != null) {
|
||||||
if (obj.ciraConnection == null) { obj.socket.destroy(); } else { obj.socket.close(); }
|
try {
|
||||||
|
if (obj.ciraConnection == null) {
|
||||||
|
obj.socket.destroy();
|
||||||
|
} else {
|
||||||
|
if (obj.cirasocket != null) { obj.cirasocket.close(); } else { obj.socket.close(); }
|
||||||
|
}
|
||||||
|
} catch (ex) { }
|
||||||
obj.socket = null;
|
obj.socket = null;
|
||||||
|
obj.cirasocket = null;
|
||||||
}
|
}
|
||||||
if (obj.pendingAjaxCall.length > 0) {
|
if (obj.pendingAjaxCall.length > 0) {
|
||||||
var r = obj.pendingAjaxCall.shift(), retry = r[5];
|
var r = obj.pendingAjaxCall.shift(), retry = r[5];
|
||||||
|
@ -376,14 +439,22 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, ciraCon
|
||||||
|
|
||||||
obj.xxOnSocketTimeout = function () {
|
obj.xxOnSocketTimeout = function () {
|
||||||
if (obj.socket != null) {
|
if (obj.socket != null) {
|
||||||
if (obj.ciraConnection == null) { obj.socket.destroy(); } else { obj.socket.close(); }
|
try {
|
||||||
|
if (obj.ciraConnection == null) {
|
||||||
|
obj.socket.destroy();
|
||||||
|
} else {
|
||||||
|
if (obj.cirasocket != null) { obj.cirasocket.close(); } else { obj.socket.close(); }
|
||||||
|
}
|
||||||
|
} catch (ex) { }
|
||||||
obj.socket = null;
|
obj.socket = null;
|
||||||
|
obj.cirasocket = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NODE.js specific private method
|
// NODE.js specific private method
|
||||||
obj.xxSend = function (x) {
|
obj.xxSend = function (x) {
|
||||||
if (obj.socketState == 2) { obj.socket.write(Buffer.from(x, "binary")); }
|
//console.log('xxSend', x);
|
||||||
|
if (obj.socketState == 2) { obj.socket.write(Buffer.from(x, 'binary')); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancel all pending queries with given status
|
// Cancel all pending queries with given status
|
||||||
|
|
|
@ -49,6 +49,9 @@ module.exports.CreateAmtManager = function(parent) {
|
||||||
// If the connection type we are using is not longer valid, remove our managed device.
|
// If the connection type we are using is not longer valid, remove our managed device.
|
||||||
if ((dev != null) && (dev.conntype != null) && ((dev.conntype & event.conn) == 0)) { removeDevice(event.nodeid); dev = null; }
|
if ((dev != null) && (dev.conntype != null) && ((dev.conntype & event.conn) == 0)) { removeDevice(event.nodeid); dev = null; }
|
||||||
|
|
||||||
|
// Debug line, to only manage CIRA/Relay connections
|
||||||
|
//if ((event.conn & 10) == 0) return;
|
||||||
|
|
||||||
// Create or update a managed device
|
// Create or update a managed device
|
||||||
if ((event.conn & 14) != 0) { // connectType: Bitmask, 1 = MeshAgent, 2 = Intel AMT CIRA, 4 = Intel AMT local, 8 = Intel AMT Relay, 16 = MQTT
|
if ((event.conn & 14) != 0) { // connectType: Bitmask, 1 = MeshAgent, 2 = Intel AMT CIRA, 4 = Intel AMT local, 8 = Intel AMT Relay, 16 = MQTT
|
||||||
// We have an OOB connection to Intel AMT, update our information
|
// We have an OOB connection to Intel AMT, update our information
|
||||||
|
@ -224,7 +227,6 @@ module.exports.CreateAmtManager = function(parent) {
|
||||||
// Connect now
|
// Connect now
|
||||||
//console.log('CIRA-Connect', (dotls == 1)?"TLS":"NoTLS", dev.name, dev.host, user, pass);
|
//console.log('CIRA-Connect', (dotls == 1)?"TLS":"NoTLS", dev.name, dev.host, user, pass);
|
||||||
var comm;
|
var comm;
|
||||||
dotls = 0; // TODO: We don't support TLS with CIRA/Relay/LMS connections yet. Remove this when we do.
|
|
||||||
if (dotls == 1) {
|
if (dotls == 1) {
|
||||||
comm = CreateWsmanComm(dev.nodeid, 16993, user, pass, 1, null, ciraconn); // Perform TLS
|
comm = CreateWsmanComm(dev.nodeid, 16993, user, pass, 1, null, ciraconn); // Perform TLS
|
||||||
comm.xtlsFingerprint = 0; // Perform no certificate checking
|
comm.xtlsFingerprint = 0; // Perform no certificate checking
|
||||||
|
@ -253,7 +255,6 @@ module.exports.CreateAmtManager = function(parent) {
|
||||||
|
|
||||||
// Connect now
|
// Connect now
|
||||||
var comm;
|
var comm;
|
||||||
dev.tlsfail = true; // TODO: We don't support TLS with CIRA/Relay/LMS connections yet. Remove this when we do.
|
|
||||||
if (dev.tlsfail !== true) {
|
if (dev.tlsfail !== true) {
|
||||||
//console.log('Relay-Connect', "TLS", dev.name, dev.host, user, pass);
|
//console.log('Relay-Connect', "TLS", dev.name, dev.host, user, pass);
|
||||||
comm = CreateWsmanComm(dev.nodeid, 16993, user, pass, 1, null, ciraconn); // Perform TLS
|
comm = CreateWsmanComm(dev.nodeid, 16993, user, pass, 1, null, ciraconn); // Perform TLS
|
||||||
|
|
|
@ -854,7 +854,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||||
var cirachannel = socket.tag.channels[RecipientChannel];
|
var cirachannel = socket.tag.channels[RecipientChannel];
|
||||||
if (cirachannel == null) { console.log("MPS Error in CHANNEL_DATA: Unable to find channelid " + RecipientChannel); return 9 + LengthOfData; }
|
if (cirachannel == null) { console.log("MPS Error in CHANNEL_DATA: Unable to find channelid " + RecipientChannel); return 9 + LengthOfData; }
|
||||||
cirachannel.amtpendingcredits += LengthOfData;
|
cirachannel.amtpendingcredits += LengthOfData;
|
||||||
if (cirachannel.onData) cirachannel.onData(cirachannel, data.substring(9, 9 + LengthOfData));
|
if (cirachannel.onData) { cirachannel.onData(cirachannel, Buffer.from(data.substring(9, 9 + LengthOfData), 'binary')); }
|
||||||
if (cirachannel.amtpendingcredits > (cirachannel.ciraWindow / 2)) {
|
if (cirachannel.amtpendingcredits > (cirachannel.ciraWindow / 2)) {
|
||||||
SendChannelWindowAdjust(cirachannel.socket, cirachannel.amtchannelid, cirachannel.amtpendingcredits); // Adjust the buffer window
|
SendChannelWindowAdjust(cirachannel.socket, cirachannel.amtchannelid, cirachannel.amtpendingcredits); // Adjust the buffer window
|
||||||
cirachannel.amtpendingcredits = 0;
|
cirachannel.amtpendingcredits = 0;
|
||||||
|
@ -960,8 +960,8 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function SendChannelData(socket, channelid, data) {
|
function SendChannelData(socket, channelid, data) {
|
||||||
parent.debug('mpscmddata', '<-- CHANNEL_DATA', channelid, data.length);
|
parent.debug('mpscmddata', '<-- CHANNEL_DATA', channelid, data.length, Buffer.from(data, 'binary').toString('hex'));
|
||||||
Write(socket, String.fromCharCode(APFProtocol.CHANNEL_DATA) + common.IntToStr(channelid) + common.IntToStr(data.length) + data);
|
Write(socket, String.fromCharCode(APFProtocol.CHANNEL_DATA) + common.IntToStr(channelid) + common.IntToStr(data.length) + ((typeof data == 'string') ? data : data.toString('binary')));
|
||||||
}
|
}
|
||||||
|
|
||||||
function SendChannelWindowAdjust(socket, channelid, bytestoadd) {
|
function SendChannelWindowAdjust(socket, channelid, bytestoadd) {
|
||||||
|
@ -987,6 +987,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function Write(socket, data) {
|
function Write(socket, data) {
|
||||||
|
try {
|
||||||
if (args.mpsdebug) {
|
if (args.mpsdebug) {
|
||||||
// Print out sent bytes
|
// Print out sent bytes
|
||||||
var buf = Buffer.from(data, 'binary');
|
var buf = Buffer.from(data, 'binary');
|
||||||
|
@ -995,6 +996,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||||
} else {
|
} else {
|
||||||
if (socket.websocket == 1) { socket.send(Buffer.from(data, 'binary')); } else { socket.write(Buffer.from(data, 'binary')); }
|
if (socket.websocket == 1) { socket.send(Buffer.from(data, 'binary')); } else { socket.write(Buffer.from(data, 'binary')); }
|
||||||
}
|
}
|
||||||
|
} catch (ex) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a CIRA/Relay/LMS connection to a nodeid, use the best possible connection, CIRA first, Relay second, LMS third.
|
// Returns a CIRA/Relay/LMS connection to a nodeid, use the best possible connection, CIRA first, Relay second, LMS third.
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -4895,6 +4895,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
putstore('_collapse', JSON.stringify(CollapsedGroups));
|
||||||
mainUpdate(4);
|
mainUpdate(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue