A working serverside AMT API via 3 different modes, namely mode 1 (AMT Direct), mode 2 (CIRA) and mode 3 (APF bridge)
A working serverside AMT API via 3 different modes, namely mode 1 (AMT Direct), mode 2 (CIRA) and mode 3 (APF bridge)
jsastriawan committed
Sep 20, 2019 at 17:21 UTC
d03716b73acea0794ff863a56db7d06b9fc865ad
6 files changed
+94
-35
agents/modules_meshcore/apfclient.js
+7
-5
@@ -332,7 +332,7 @@ function CreateAPFClient(parent, args) {
332
if (pfwd_ports.indexOf(p_res.target_port) >= 0) {
333
// connect socket to that port
334
obj.downlinks[p_res.sender_chan] = obj.net.createConnection({ host: obj.args.clientaddress, port: p_res.target_port }, function () {
335
- obj.downlinks[p_res.sender_chan].setEncoding('binary');//assume everything is binary, not interpreting
335
+ //obj.downlinks[p_res.sender_chan].setEncoding('binary');//assume everything is binary, not interpreting
336
SendChannelOpenConfirm(socket.ws, p_res);
337
});
338
@@ -348,8 +348,10 @@ function CreateAPFClient(parent, args) {
348
obj.downlinks[p_res.sender_chan].on('end', function () {
349
if (obj.downlinks[p_res.sender_chan]) {
350
try {
351
+ Debug("Socket ends.");
352
SendChannelClose(socket.ws, p_res.sender_chan);
352
- delete obj.downlinks[p_res.sender_chan];
353
+ // add some delay before removing... otherwise race condition
354
+ setTimeout(function () { delete obj.downlinks[p_res.sender_chan];},100);
355
} catch (e) {
356
Debug("Downlink connection exception: " + e);
357
}
@@ -449,14 +451,14 @@ function CreateAPFClient(parent, args) {
451
452
function SendChannelData(socket, chan, len, data) {
453
var buf = String.fromCharCode(APFProtocol.CHANNEL_DATA) + IntToStr(chan) + IntToStr(len) + data;
452
- socket.write(Buffer.from(buf, 'binary'));
454
+ socket.write(buf);
455
Debug("APF: Send ChannelData: " + rstr2hex(buf));
456
}
457
458
function SendChannelClose(socket, chan) {
459
var buf = String.fromCharCode(APFProtocol.CHANNEL_CLOSE) + IntToStr(chan);
458
- socket.write(Buffer.from(buf, 'binary'));
459
- Debug("APF: Send ChannelClose: " + rstr2hex(buf));
460
+ socket.write(buf);
461
+ Debug("APF: Send ChannelClose ");
462
}
463
464
obj.connect = function () {
agents/modules_meshcore_min/apfclient.min.js
+1
-1
@@ -1 +1 @@
1
-function CreateAPFClient(q,e){var o={};o.parent=q;o.args=e;o.http=require("http");o.net=require("net");o.forwardClient=null;o.downlinks={};o.pfwd_idx=0;o.timer=null;function u(K,J){return(K.charCodeAt(J)*16777216)+(K.charCodeAt(J+1)<<16)+(K.charCodeAt(J+2)<<8)+K.charCodeAt(J+3)}function n(J){return String.fromCharCode((J>>24)&255,(J>>16)&255,(J>>8)&255,J&255)}function m(J){var L="",K=(""+J).match(/../g),M;while(M=K.shift()){L+=String.fromCharCode("0x"+M)}return L}function h(J){return(J+256).toString(16).substr(-2).toUpperCase()}function w(K){var L="",J;for(J=0;J<K.length;J++){L+=h(K.charCodeAt(J))}return L}function j(J){return(J/256+1/512).toString(16).substring(2,4)}function g(K){var L="",J;for(J=0;J<K.length;J++){L+=j(K[J])}return L}function k(J){if(o.parent.debug){console.log(J)}}var i={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};o.cirastate=i.INITIAL;var v={REDIR_UNKNOWN:0,REDIR_SOL:1,REDIR_KVM:2,REDIR_IDER:3};o.RedirectStartSol=String.fromCharCode(16,0,0,0,83,79,76,32);o.RedirectStartKvm=String.fromCharCode(16,1,0,0,75,86,77,82);o.RedirectStartIder=String.fromCharCode(16,0,0,0,73,68,69,82);var s=[16992,623,16994,5900];var d={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};var c={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 a={ADMINISTRATIVELY_PROHIBITED:1,CONNECT_FAILED:2,UNKNOWN_CHANNEL_TYPE:3,RESOURCE_SHORTAGE:4,};var b={AdministrativelyProhibited:1,ConnectFailed:2,UnknownChannelType:3,ResourceShortage:4,};o.onSecureConnect=function p(K,L,J){k("APF Secure WebSocket connected.");o.forwardClient.tag={accumulator:[]};o.forwardClient.ws=L;o.forwardClient.ws.on("end",function(){k("APF: Connection is closing.");if(o.timer!=null){clearInterval(o.timer);o.timer=null}});o.forwardClient.ws.on("data",function(M){o.forwardClient.tag.accumulator+=m(g(M));try{var O=0;do{O=t(o.forwardClient);if(O>0){o.forwardClient.tag.accumulator=o.forwardClient.tag.accumulator.slice(O)}if(o.cirastate==i.FAILED){k("APF: in a failed state, destroying socket.");o.forwardClient.ws.end()}}while(O>0)}catch(N){k(N)}});o.forwardClient.ws.on("error",function(M){k("APF: Connection error, ending connecting.");if(o.timer!=null){clearInterval(o.timer);o.timer=null}});o.state=i.INITIAL;F(o.forwardClient.ws,o.args.clientuuid);G(o.forwardClient.ws,"auth@amt.intel.com")};function l(J){return J.substring(6,8)+J.substring(4,6)+J.substring(2,4)+J.substring(0,2)+"-"+J.substring(10,12)+J.substring(8,10)+"-"+J.substring(14,16)+J.substring(12,14)+"-"+J.substring(16,20)+"-"+J.substring(20)}function I(K){K=K.replace(/-/g,"");var J=K.substring(6,8)+K.substring(4,6)+K.substring(2,4)+K.substring(0,2);J+=K.substring(10,12)+K.substring(8,10)+K.substring(14,16)+K.substring(12,14)+K.substring(16,20)+K.substring(20);return J}function f(K){var L="";for(var J=0;J<K;J++){L+=String.fromCharCode(0&255)}return L}function F(L,M){var J=I(M);var K=String.fromCharCode(d.PROTOCOLVERSION)+""+n(1)+n(0)+n(0)+m(J)+f(64);L.write(K);k("APF: Send protocol version 1 0 "+M);o.cirastate=i.PROTOCOL_VERSION_SENT}function G(L,K){var J=String.fromCharCode(d.SERVICE_REQUEST)+n(K.length)+K;L.write(J);k("APF: Send service request "+K);if(K=="auth@amt.intel.com"){o.cirastate=i.AUTH_SERVICE_REQUEST_SENT}else{if(K=="pfwd@amt.intel.com"){o.cirastate=i.PFWD_SERVICE_REQUEST_SENT}}}function H(M,N,K){var L="pfwd@amt.intel.com";var J=String.fromCharCode(d.USERAUTH_REQUEST)+n(N.length)+N+n(L.length)+L;J+=n(8)+"password";J+=f(1)+n(K.length)+K;M.write(J);k("APF: Send username password authentication to MPS");o.cirastate=i.AUTH_REQUEST_SENT}function C(M,J,K){var N="tcpip-forward";var L=String.fromCharCode(d.GLOBAL_REQUEST)+n(N.length)+N+f(1,1);L+=n(J.length)+J+n(K);M.write(L);k("APF: Send tcpip-forward "+J+":"+K);o.cirastate=i.GLOBAL_REQUEST_SENT}function E(K){var J=String.fromCharCode(d.KEEPALIVE_REQUEST)+n(255);K.write(J);k("APF: Send keepalive request")}function D(L,J){var K=String.fromCharCode(d.KEEPALIVE_REPLY)+n(J);L.write(K);k("APF: Send keepalive reply")}function t(U){var L=U.tag.accumulator.charCodeAt(0);var O=U.tag.accumulator.length;var M=U.tag.accumulator;if(O==0){return 0}switch(L){case d.SERVICE_ACCEPT:var T=u(M,1);var S=M.substring(5,6+T);k("APF: Service request to "+S+" accepted.");if(S=="auth@amt.intel.com"){if(o.cirastate>=i.AUTH_SERVICE_REQUEST_SENT){H(U.ws,o.args.mpsuser,o.args.mpspass)}}else{if(S=="pfwd@amt.intel.com"){if(o.cirastate>=i.PFWD_SERVICE_REQUEST_SENT){C(U.ws,o.args.clientname,s[o.pfwd_idx++])}}}return 5+T;case d.REQUEST_SUCCESS:if(O>=5){var Q=u(M,1);k("APF: Request to port forward "+Q+" successful.");if(o.pfwd_idx<s.length){C(U.ws,o.args.clientname,s[o.pfwd_idx++])}else{k("APF: Start keep alive for every "+o.args.mpskeepalive+" ms.");o.timer=setInterval(function(){E(o.forwardClient.ws)},o.args.mpskeepalive)}return 5}k("APF: Request successful.");return 1;case d.USERAUTH_SUCCESS:k("APF: User Authentication successful");G(U.ws,"pfwd@amt.intel.com");return 1;case d.USERAUTH_FAILURE:k("APF: User Authentication failed");o.cirastate=i.FAILED;return 14;case d.KEEPALIVE_REQUEST:k("APF: Keep Alive Request with cookie: "+u(M,1));D(U.ws,u(M,1));return 5;case d.KEEPALIVE_REPLY:k("APF: Keep Alive Reply with cookie: "+u(M,1));return 5;case d.CHANNEL_OPEN:var P=r(M);k("APF: CHANNEL_OPEN request: "+JSON.stringify(P));if(s.indexOf(P.target_port)>=0){o.downlinks[P.sender_chan]=o.net.createConnection({host:o.args.clientaddress,port:P.target_port},function(){o.downlinks[P.sender_chan].setEncoding("binary");z(U.ws,P)});o.downlinks[P.sender_chan].on("data",function(V){y(U.ws,P.sender_chan,V.length,V)});o.downlinks[P.sender_chan].on("error",function(V){k("Downlink connection error: "+V)});o.downlinks[P.sender_chan].on("end",function(){if(o.downlinks[P.sender_chan]){try{x(U.ws,P.sender_chan);delete o.downlinks[P.sender_chan]}catch(V){k("Downlink connection exception: "+V)}}})}else{A(U.ws,P)}return P.len;case d.CHANNEL_OPEN_CONFIRMATION:k("APF: CHANNEL_OPEN_CONFIRMATION");return 17;case d.CHANNEL_CLOSE:var R=u(M,1);k("APF: CHANNEL_CLOSE: "+R);x(U.ws,R);try{o.downlinks[R].end();delete o.downlinks[R]}catch(N){}return 5;case d.CHANNEL_DATA:k("APF: CHANNEL_DATA: "+JSON.stringify(w(M)));var R=u(M,1);var K=u(M,5);var J=M.substring(9,9+K);if(o.downlinks[R]){try{o.downlinks[R].write(J,"binary",function(){k("Write completed.");B(U.ws,R,K)})}catch(N){k("Cannot forward data to downlink socket.")}}return 9+K;case d.CHANNEL_WINDOW_ADJUST:k("APF: CHANNEL_WINDOW_ADJUST ");return 9;default:k("CMD: "+L+" is not implemented.");o.cirastate=i.FAILED;return 0}}function r(L){var N={len:0,cmd:d.CHANNEL_OPEN,chan_type:"",sender_chan:0,window_size:0,target_address:"",target_port:0,origin_address:"",origin_port:0,};var K=u(L,1);N.chan_type=L.substring(5,5+K);N.sender_chan=u(L,5+K);N.window_size=u(L,9+K);var J=u(L,17+K);N.target_address=L.substring(21+K,21+K+J);N.target_port=u(L,21+K+J);var M=u(L,25+K+J);N.origin_address=L.substring(29+K+J,29+K+J+M);N.origin_port=u(L,29+K+J+M);N.len=33+K+J+M;return N}function A(L,J){var K=String.fromCharCode(d.CHANNEL_OPEN_FAILURE)+n(J.sender_chan)+n(2)+n(0)+n(0);L.write(K);k("APF: Send ChannelOpenFailure")}function z(L,J){var K=String.fromCharCode(d.CHANNEL_OPEN_CONFIRMATION)+n(J.sender_chan)+n(J.sender_chan)+n(J.window_size)+n(4294967295);L.write(K);k("APF: Send ChannelOpenConfirmation")}function B(M,J,L){var K=String.fromCharCode(d.CHANNEL_WINDOW_ADJUST)+n(J)+n(L);M.write(K);k("APF: Send ChannelWindowAdjust: "+w(K))}function y(N,K,M,L){var J=String.fromCharCode(d.CHANNEL_DATA)+n(K)+n(M)+L;N.write(Buffer.from(J,"binary"));k("APF: Send ChannelData: "+w(J))}function x(L,K){var J=String.fromCharCode(d.CHANNEL_CLOSE)+n(K);L.write(Buffer.from(J,"binary"));k("APF: Send ChannelClose: "+w(J))}o.connect=function(){if(o.forwardClient!=null){try{o.forwardClient.ws.end()}catch(J){k(J)}}o.cirastate=i.INITIAL;o.pfwd_idx=0;var K=o.http.parseUri(o.args.mpsurl);K.rejectUnauthorized=0;o.forwardClient=o.http.request(K);o.forwardClient.upgrade=o.onSecureConnect;o.forwardClient.end()};o.disconnect=function(){try{o.forwardClient.ws.end()}catch(J){k(J)}};return o}module.exports=CreateAPFClient;
\ No newline at end of file
1
+function CreateAPFClient(q,e){var o={};o.parent=q;o.args=e;o.http=require("http");o.net=require("net");o.forwardClient=null;o.downlinks={};o.pfwd_idx=0;o.timer=null;function u(K,J){return(K.charCodeAt(J)*16777216)+(K.charCodeAt(J+1)<<16)+(K.charCodeAt(J+2)<<8)+K.charCodeAt(J+3)}function n(J){return String.fromCharCode((J>>24)&255,(J>>16)&255,(J>>8)&255,J&255)}function m(J){var L="",K=(""+J).match(/../g),M;while(M=K.shift()){L+=String.fromCharCode("0x"+M)}return L}function h(J){return(J+256).toString(16).substr(-2).toUpperCase()}function w(K){var L="",J;for(J=0;J<K.length;J++){L+=h(K.charCodeAt(J))}return L}function j(J){return(J/256+1/512).toString(16).substring(2,4)}function g(K){var L="",J;for(J=0;J<K.length;J++){L+=j(K[J])}return L}function k(J){if(o.parent.debug){console.log(J)}}var i={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};o.cirastate=i.INITIAL;var v={REDIR_UNKNOWN:0,REDIR_SOL:1,REDIR_KVM:2,REDIR_IDER:3};o.RedirectStartSol=String.fromCharCode(16,0,0,0,83,79,76,32);o.RedirectStartKvm=String.fromCharCode(16,1,0,0,75,86,77,82);o.RedirectStartIder=String.fromCharCode(16,0,0,0,73,68,69,82);var s=[16992,623,16994,5900];var d={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};var c={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 a={ADMINISTRATIVELY_PROHIBITED:1,CONNECT_FAILED:2,UNKNOWN_CHANNEL_TYPE:3,RESOURCE_SHORTAGE:4,};var b={AdministrativelyProhibited:1,ConnectFailed:2,UnknownChannelType:3,ResourceShortage:4,};o.onSecureConnect=function p(K,L,J){k("APF Secure WebSocket connected.");o.forwardClient.tag={accumulator:[]};o.forwardClient.ws=L;o.forwardClient.ws.on("end",function(){k("APF: Connection is closing.");if(o.timer!=null){clearInterval(o.timer);o.timer=null}});o.forwardClient.ws.on("data",function(M){o.forwardClient.tag.accumulator+=m(g(M));try{var O=0;do{O=t(o.forwardClient);if(O>0){o.forwardClient.tag.accumulator=o.forwardClient.tag.accumulator.slice(O)}if(o.cirastate==i.FAILED){k("APF: in a failed state, destroying socket.");o.forwardClient.ws.end()}}while(O>0)}catch(N){k(N)}});o.forwardClient.ws.on("error",function(M){k("APF: Connection error, ending connecting.");if(o.timer!=null){clearInterval(o.timer);o.timer=null}});o.state=i.INITIAL;F(o.forwardClient.ws,o.args.clientuuid);G(o.forwardClient.ws,"auth@amt.intel.com")};function l(J){return J.substring(6,8)+J.substring(4,6)+J.substring(2,4)+J.substring(0,2)+"-"+J.substring(10,12)+J.substring(8,10)+"-"+J.substring(14,16)+J.substring(12,14)+"-"+J.substring(16,20)+"-"+J.substring(20)}function I(K){K=K.replace(/-/g,"");var J=K.substring(6,8)+K.substring(4,6)+K.substring(2,4)+K.substring(0,2);J+=K.substring(10,12)+K.substring(8,10)+K.substring(14,16)+K.substring(12,14)+K.substring(16,20)+K.substring(20);return J}function f(K){var L="";for(var J=0;J<K;J++){L+=String.fromCharCode(0&255)}return L}function F(L,M){var J=I(M);var K=String.fromCharCode(d.PROTOCOLVERSION)+""+n(1)+n(0)+n(0)+m(J)+f(64);L.write(K);k("APF: Send protocol version 1 0 "+M);o.cirastate=i.PROTOCOL_VERSION_SENT}function G(L,K){var J=String.fromCharCode(d.SERVICE_REQUEST)+n(K.length)+K;L.write(J);k("APF: Send service request "+K);if(K=="auth@amt.intel.com"){o.cirastate=i.AUTH_SERVICE_REQUEST_SENT}else{if(K=="pfwd@amt.intel.com"){o.cirastate=i.PFWD_SERVICE_REQUEST_SENT}}}function H(M,N,K){var L="pfwd@amt.intel.com";var J=String.fromCharCode(d.USERAUTH_REQUEST)+n(N.length)+N+n(L.length)+L;J+=n(8)+"password";J+=f(1)+n(K.length)+K;M.write(J);k("APF: Send username password authentication to MPS");o.cirastate=i.AUTH_REQUEST_SENT}function C(M,J,K){var N="tcpip-forward";var L=String.fromCharCode(d.GLOBAL_REQUEST)+n(N.length)+N+f(1,1);L+=n(J.length)+J+n(K);M.write(L);k("APF: Send tcpip-forward "+J+":"+K);o.cirastate=i.GLOBAL_REQUEST_SENT}function E(K){var J=String.fromCharCode(d.KEEPALIVE_REQUEST)+n(255);K.write(J);k("APF: Send keepalive request")}function D(L,J){var K=String.fromCharCode(d.KEEPALIVE_REPLY)+n(J);L.write(K);k("APF: Send keepalive reply")}function t(U){var L=U.tag.accumulator.charCodeAt(0);var O=U.tag.accumulator.length;var M=U.tag.accumulator;if(O==0){return 0}switch(L){case d.SERVICE_ACCEPT:var T=u(M,1);var S=M.substring(5,6+T);k("APF: Service request to "+S+" accepted.");if(S=="auth@amt.intel.com"){if(o.cirastate>=i.AUTH_SERVICE_REQUEST_SENT){H(U.ws,o.args.mpsuser,o.args.mpspass)}}else{if(S=="pfwd@amt.intel.com"){if(o.cirastate>=i.PFWD_SERVICE_REQUEST_SENT){C(U.ws,o.args.clientname,s[o.pfwd_idx++])}}}return 5+T;case d.REQUEST_SUCCESS:if(O>=5){var Q=u(M,1);k("APF: Request to port forward "+Q+" successful.");if(o.pfwd_idx<s.length){C(U.ws,o.args.clientname,s[o.pfwd_idx++])}else{k("APF: Start keep alive for every "+o.args.mpskeepalive+" ms.");o.timer=setInterval(function(){E(o.forwardClient.ws)},o.args.mpskeepalive)}return 5}k("APF: Request successful.");return 1;case d.USERAUTH_SUCCESS:k("APF: User Authentication successful");G(U.ws,"pfwd@amt.intel.com");return 1;case d.USERAUTH_FAILURE:k("APF: User Authentication failed");o.cirastate=i.FAILED;return 14;case d.KEEPALIVE_REQUEST:k("APF: Keep Alive Request with cookie: "+u(M,1));D(U.ws,u(M,1));return 5;case d.KEEPALIVE_REPLY:k("APF: Keep Alive Reply with cookie: "+u(M,1));return 5;case d.CHANNEL_OPEN:var P=r(M);k("APF: CHANNEL_OPEN request: "+JSON.stringify(P));if(s.indexOf(P.target_port)>=0){o.downlinks[P.sender_chan]=o.net.createConnection({host:o.args.clientaddress,port:P.target_port},function(){z(U.ws,P)});o.downlinks[P.sender_chan].on("data",function(V){y(U.ws,P.sender_chan,V.length,V)});o.downlinks[P.sender_chan].on("error",function(V){k("Downlink connection error: "+V)});o.downlinks[P.sender_chan].on("end",function(){if(o.downlinks[P.sender_chan]){try{k("Socket ends.");x(U.ws,P.sender_chan);setTimeout(function(){delete o.downlinks[P.sender_chan]},100)}catch(V){k("Downlink connection exception: "+V)}}})}else{A(U.ws,P)}return P.len;case d.CHANNEL_OPEN_CONFIRMATION:k("APF: CHANNEL_OPEN_CONFIRMATION");return 17;case d.CHANNEL_CLOSE:var R=u(M,1);k("APF: CHANNEL_CLOSE: "+R);x(U.ws,R);try{o.downlinks[R].end();delete o.downlinks[R]}catch(N){}return 5;case d.CHANNEL_DATA:k("APF: CHANNEL_DATA: "+JSON.stringify(w(M)));var R=u(M,1);var K=u(M,5);var J=M.substring(9,9+K);if(o.downlinks[R]){try{o.downlinks[R].write(J,"binary",function(){k("Write completed.");B(U.ws,R,K)})}catch(N){k("Cannot forward data to downlink socket.")}}return 9+K;case d.CHANNEL_WINDOW_ADJUST:k("APF: CHANNEL_WINDOW_ADJUST ");return 9;default:k("CMD: "+L+" is not implemented.");o.cirastate=i.FAILED;return 0}}function r(L){var N={len:0,cmd:d.CHANNEL_OPEN,chan_type:"",sender_chan:0,window_size:0,target_address:"",target_port:0,origin_address:"",origin_port:0,};var K=u(L,1);N.chan_type=L.substring(5,5+K);N.sender_chan=u(L,5+K);N.window_size=u(L,9+K);var J=u(L,17+K);N.target_address=L.substring(21+K,21+K+J);N.target_port=u(L,21+K+J);var M=u(L,25+K+J);N.origin_address=L.substring(29+K+J,29+K+J+M);N.origin_port=u(L,29+K+J+M);N.len=33+K+J+M;return N}function A(L,J){var K=String.fromCharCode(d.CHANNEL_OPEN_FAILURE)+n(J.sender_chan)+n(2)+n(0)+n(0);L.write(K);k("APF: Send ChannelOpenFailure")}function z(L,J){var K=String.fromCharCode(d.CHANNEL_OPEN_CONFIRMATION)+n(J.sender_chan)+n(J.sender_chan)+n(J.window_size)+n(4294967295);L.write(K);k("APF: Send ChannelOpenConfirmation")}function B(M,J,L){var K=String.fromCharCode(d.CHANNEL_WINDOW_ADJUST)+n(J)+n(L);M.write(K);k("APF: Send ChannelWindowAdjust: "+w(K))}function y(N,K,M,L){var J=String.fromCharCode(d.CHANNEL_DATA)+n(K)+n(M)+L;N.write(J);k("APF: Send ChannelData: "+w(J))}function x(L,K){var J=String.fromCharCode(d.CHANNEL_CLOSE)+n(K);L.write(J);k("APF: Send ChannelClose ")}o.connect=function(){if(o.forwardClient!=null){try{o.forwardClient.ws.end()}catch(J){k(J)}}o.cirastate=i.INITIAL;o.pfwd_idx=0;var K=o.http.parseUri(o.args.mpsurl);K.rejectUnauthorized=0;o.forwardClient=o.http.request(K);o.forwardClient.upgrade=o.onSecureConnect;o.forwardClient.end()};o.disconnect=function(){try{o.forwardClient.ws.end()}catch(J){k(J)}};return o}module.exports=CreateAPFClient;
\ No newline at end of file
amt/amt-wsman-comm.js
+15
-24
@@ -1,6 +1,6 @@
1
/**
2
* @description Intel(r) AMT WSMAN communication using Node.js TLS
3
-* @author Ylian Saint-Hilaire
3
+* @author Ylian Saint-Hilaire/Joko Sastriawan
4
* @version v0.2.0b
5
*/
6
@@ -39,7 +39,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent,
39
obj.xtls = tls;
40
obj.xtlsoptions = tlsoptions;
41
obj.parent = parent;
42
- obj.mode = mode;//0: webrelay; 1: direct, 2: CIRA, 3: APF relay
42
+ obj.mode = mode;//1: direct, 2: CIRA, 3: APF relay
43
obj.xtlsFingerprint;
44
obj.xtlsCertificate = null;
45
obj.xtlsCheck = 0; // 0 = No TLS, 1 = CA Checked, 2 = Pinned, 3 = Untrusted
@@ -167,17 +167,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent,
167
obj.socketState = 1;
168
obj.kerberosDone = 0;
169
170
- if (obj.mode==0 && obj.xtlsoptions && obj.xtlsoptions.meshServerConnect) { //Webrelay
171
- // Use the websocket wrapper to connect to MeshServer server
172
- obj.socket = CreateWebSocketWrapper(obj.xtlsoptions.host, obj.xtlsoptions.port, '/webrelay.ashx?user=' + encodeURIComponent(obj.xtlsoptions.username) + '&pass=' + encodeURIComponent(obj.xtlsoptions.password) + '&host=' + encodeURIComponent(obj.host) + '&p=1&tls1only=' + obj.xtlsMethod, obj.xtlsoptions.xtlsFingerprint);
173
- obj.socket.setEncoding('binary');
174
- obj.socket.setTimeout(6000); // Set socket idle timeout
175
- obj.socket.ondata = obj.xxOnSocketData;
176
- obj.socket.onclose = function () { if (obj.xtlsDataReceived == false) { obj.xtlsMethod = 1 - obj.xtlsMethod; } obj.xxOnSocketClosed(); }
177
- obj.socket.ontimeout = function () { if (obj.xtlsDataReceived == false) { obj.xtlsMethod = 1 - obj.xtlsMethod; } obj.xxOnSocketClosed(); }
178
- obj.socket.connect(obj.xxOnSocketConnected);
179
- obj.socket.setNoDelay(true); // Disable nagle. We will encode each WSMAN request as a single send block and want to send it at once. This may help Intel AMT handle pipelining?
180
- } else if (obj.mode==1 ) { //Direct
170
+ if (obj.mode==1 ) { //Direct
171
if (obj.xtls != 1) {
172
// Connect without TLS
173
obj.socket = new obj.net.Socket();
@@ -214,7 +204,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent,
204
obj.socket = obj.parent.apfserver.SetupCiraChannel(apfconn, obj.port);
205
}
206
obj.socket.onData = function (ccon, data) {
217
- _OnSocketData(data);
207
+ obj.xxOnSocketData(data);
208
}
209
210
obj.socket.onStateChange = function (ccon, state) {
@@ -225,11 +215,11 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent,
215
obj.socketHeader = null;
216
obj.socketData = '';
217
obj.socketState = 0;
228
- _OnSocketClosed();
218
+ obj.xxOnSocketClosed();
219
} catch (e) { }
220
} else if (state == 2) {
221
// channel open success
232
- _OnSocketConnected();
222
+ obj.xxOnSocketConnected();
223
}
224
}
225
}
@@ -289,8 +279,8 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent,
279
280
// NODE.js specific private method
281
obj.xxOnSocketData = function (data) {
292
- obj.xtlsDataReceived = true;
293
- if (urlvars && urlvars['wsmantrace']) { console.log("WSMAN-RECV(" + data.length + "): " + data); }
282
+ //console.log("RECV:"+data);
283
+ obj.xtlsDataReceived = true;
284
if (typeof data === 'object') {
285
// This is an ArrayBuffer, convert it to a string array (used in IE)
286
var binary = "", bytes = new Uint8Array(data), length = bytes.byteLength;
@@ -305,7 +295,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent,
295
if (obj.socketParseState == 0) {
296
var headersize = obj.socketAccumulator.indexOf("\r\n\r\n");
297
if (headersize < 0) return;
308
- //obj.Debug(obj.socketAccumulator.substring(0, headersize)); // Display received HTTP header
298
+ //obj.Debug("Header: "+obj.socketAccumulator.substring(0, headersize)); // Display received HTTP header
299
obj.socketHeader = obj.socketAccumulator.substring(0, headersize).split("\r\n");
300
if (obj.amtVersion == null) { for (var i in obj.socketHeader) { if (obj.socketHeader[i].indexOf('Server: Intel(R) Active Management Technology ') == 0) { obj.amtVersion = obj.socketHeader[i].substring(46); } } }
301
obj.socketAccumulator = obj.socketAccumulator.substring(headersize + 4);
@@ -361,8 +351,10 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent,
351
var s = parseInt(header.Directive[1]);
352
if (isNaN(s)) s = 500;
353
if (s == 401 && ++(obj.authcounter) < 3) {
364
- obj.challengeParams = obj.parseDigest(header['www-authenticate']); // Set the digest parameters, after this, the socket will close and we will auto-retry
365
- obj.socket.end();
354
+ obj.challengeParams = obj.parseDigest(header['www-authenticate']); // Set the digest parameters, after this, the socket will close and we will auto-retry
355
+ if (obj.mode==1) {
356
+ obj.socket.end();
357
+ }
358
} else {
359
var r = obj.pendingAjaxCall.shift();
360
if (r == null || r.length < 1) { console.log("pendingAjaxCall error, " + r); return; }
@@ -378,7 +370,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent,
370
obj.xxOnSocketClosed = function (data) {
371
//obj.Debug("xxOnSocketClosed");
372
obj.socketState = 0;
381
- if (obj.socket != null) { obj.socket.destroy(); obj.socket = null; }
373
+ if (obj.mode ==1 && obj.socket != null) { obj.socket.destroy(); obj.socket = null; }
374
if (obj.pendingAjaxCall.length > 0) {
375
var r = obj.pendingAjaxCall.shift();
376
var retry = r[5];
@@ -389,8 +381,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent,
381
// NODE.js specific private method
382
obj.xxSend = function (x) {
383
if (obj.socketState == 2) {
392
- if (urlvars && urlvars['wsmantrace']) { console.log("WSMAN-SEND(" + x.length + "): " + x); }
393
- obj.socket.write(new Buffer(x, "binary"));
384
+ obj.socket.write(Buffer.from(x, "binary"));
385
}
386
}
387
amt/amt-wsman.js
+3
-3
@@ -16,12 +16,12 @@ limitations under the License.
16
17
/**
18
* @description Intel(r) AMT WSMAN Stack
19
-* @author Ylian Saint-Hilaire
19
+* @author Ylian Saint-Hilaire/Joko Sastriawan
20
* @version v0.2.0
21
*/
22
23
// Construct a MeshServer object
24
-function WsmanStackCreateService(CreateWsmanComm, host, port, user, pass, tls, extra)
24
+function WsmanStackCreateService(CreateWsmanComm, host, port, user, pass, tls, extra, parent, mode)
25
{
26
var obj = {_ObjectID: 'WSMAN'};
27
//obj.onDebugMessage = null; // Set to a function if you want to get debug messages.
@@ -38,7 +38,7 @@ function WsmanStackCreateService(CreateWsmanComm, host, port, user, pass, tls, e
38
{
39
var CreateWsmanComm = arguments[0];
40
if (CreateWsmanComm) {
41
- obj.comm = new CreateWsmanComm(host, port, user, pass, tls, extra);
41
+ obj.comm = new CreateWsmanComm(host, port, user, pass, tls, extra, parent, mode);
42
}
43
}
44
meshuser.js
+66
@@ -48,6 +48,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
48
obj.user = user;
49
obj.domain = domain;
50
51
+ // Server side amt stack
52
+ var WsmanComm = require('./amt/amt-wsman-comm.js');
53
+ var Wsman = require('./amt/amt-wsman.js');
54
+ var Amt = require('./amt/amt.js');
55
+
56
// Send a message to the user
57
//obj.send = function (data) { try { if (typeof data == 'string') { ws.send(Buffer.from(data, 'binary')); } else { ws.send(data); } } catch (e) { } }
58
@@ -2784,6 +2789,39 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2789
}
2790
break;
2791
}
2792
+ case 'amt': {
2793
+ if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
2794
+ if (common.validateInt(command.mode, 0, 3) == false) break; // Check connection mode
2795
+ // validate if communication mode is possible
2796
+ if (command.mode == null || command.mode==0) {
2797
+ break;//unsupported
2798
+ } else if (command.mode == 1) {
2799
+ var state = parent.parent.GetConnectivityState(command.nodeid);
2800
+ if ( (state == null) || (state.connectivity & 4)==0 ) break;
2801
+ } else if (command.mode == 2) {
2802
+ if (parent.parent.mpsserver.ciraConnections[command.nodeid] == null) break;
2803
+ } else if (command.mode == 3) {
2804
+ if (parent.parent.apfserver.apfConnections[command.nodeid] == null) break;
2805
+ }
2806
+ var nodeid = command.nodeid;
2807
+ if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
2808
+ // Get the device
2809
+ db.Get(nodeid, function (err, nodes) {
2810
+ if ((nodes == null) || (nodes.length != 1)) return;
2811
+ var node = nodes[0];
2812
+
2813
+ // Get the mesh for this device
2814
+ mesh = parent.meshes[node.meshid];
2815
+ if (mesh) {
2816
+ // Check if this user has rights to do this
2817
+ if (mesh.links[user._id] != null && ((mesh.links[user._id].rights & 8) != 0)) { // "Remote Control permission"
2818
+ handleAmtCommand(command, node);
2819
+ }
2820
+ }
2821
+ });
2822
+ }
2823
+ break;
2824
+ }
2825
default: {
2826
// Unknown user action
2827
console.log('Unknown action from user ' + user.name + ': ' + command.action + '.');
@@ -2912,5 +2950,33 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2950
2951
function getRandomPassword() { return Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); }
2952
2953
+ function handleAmtCommand(cmd, node) {
2954
+ if (cmd==null) return;
2955
+ var host = cmd.nodeid;
2956
+ if (cmd.mode==1) {
2957
+ host = node.host;
2958
+ }
2959
+ var tlsoptions = null;
2960
+ var wsman = new Wsman(WsmanComm, host, node.intelamt.tls? 16993: 16992, node.intelamt.user, node.intelamt.pass,
2961
+ node.intelamt.tls,tlsoptions, parent.parent, cmd.mode);
2962
+ var amt = new Amt(wsman);
2963
+ switch (cmd.command) {
2964
+ case "Get-GeneralSettings": {
2965
+ amt.Get("AMT_GeneralSettings", function(obj, name, response, status) {
2966
+ if (status==200) {
2967
+ var resp = { action: 'amt', nodeid: cmd.nodeid, command: 'Get-GeneralSettings', value: response.Body}
2968
+ ws.send(JSON.stringify(resp));
2969
+ } else {
2970
+ ws.send(JSON.stringify({"error": error}));
2971
+ }
2972
+ });
2973
+ break;
2974
+ }
2975
+ default: {
2976
+ // do nothing
2977
+ }
2978
+ }
2979
+ }
2980
+
2981
return obj;
2982
};
\ No newline at end of file
mpsserver.js
+2
-2
@@ -791,8 +791,8 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
791
return true;
792
}
793
// Send a part of the message
794
- cirachannel.sendBuffer = data.substring(cirachannel.sendcredits);
795
- SendChannelData(cirachannel.socket, cirachannel.amtchannelid, data.substring(0, cirachannel.sendcredits));
794
+ cirachannel.sendBuffer = data.toString('binary').substring(cirachannel.sendcredits);
795
+ SendChannelData(cirachannel.socket, cirachannel.amtchannelid, data.toString('binary').substring(0, cirachannel.sendcredits));
796
cirachannel.sendcredits = 0;
797
return false;
798
};