WebRTC is now used by default and fully automatic.

Ylian Saint-Hilaire committed Feb 5, 2018 at 11:56 UTC 143d4cb6475358b415dfdd0ffee8ed26991386e6
20 files changed +61 -40
agents/MeshService.exe
Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ
agents/MeshService64.exe
Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ
agents/meshagent_arm
Binary files a/agents/meshagent_arm and b/agents/meshagent_arm differ
agents/meshagent_pi
Binary files a/agents/meshagent_pi and b/agents/meshagent_pi differ
agents/meshagent_pogo
Binary files a/agents/meshagent_pogo and b/agents/meshagent_pogo differ
agents/meshagent_poky
Binary files a/agents/meshagent_poky and b/agents/meshagent_poky differ
agents/meshagent_poky64
Binary files a/agents/meshagent_poky64 and b/agents/meshagent_poky64 differ
agents/meshagent_x86
Binary files a/agents/meshagent_x86 and b/agents/meshagent_x86 differ
agents/meshagent_x86-64
Binary files a/agents/meshagent_x86-64 and b/agents/meshagent_x86-64 differ
agents/meshagent_x86-64_nokvm
Binary files a/agents/meshagent_x86-64_nokvm and b/agents/meshagent_x86-64_nokvm differ
agents/meshagent_x86_nokvm
Binary files a/agents/meshagent_x86_nokvm and b/agents/meshagent_x86_nokvm differ
agents/meshcore.js
+29 -27
@@ -683,7 +683,7 @@ function createMeshCore(agent) {
683 var obj;
684 try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON on WebRTC'); return; }
685 if (obj.type == 'close') {
686 - sendConsoleText('Tunnel #' + this.xrtc.websocket.tunnel.index + ' WebRTC control close');
686 + //sendConsoleText('Tunnel #' + this.xrtc.websocket.tunnel.index + ' WebRTC control close');
687 try { this.close(); } catch (e) { }
688 try { this.xrtc.close(); } catch (e) { }
689 }
@@ -692,7 +692,7 @@ function createMeshCore(agent) {
692 // Called when receiving control data on websocket
693 function onTunnelControlData(data) {
694 if (typeof data != 'string') return;
695 - sendConsoleText('onTunnelControlData: ' + data);
695 + //sendConsoleText('onTunnelControlData: ' + data);
696 //console.log('onTunnelControlData: ' + data);
697
698 var obj;
@@ -700,10 +700,28 @@ function createMeshCore(agent) {
700
701 if (obj.type == 'close') {
702 // We received the close on the websocket
703 - sendConsoleText('Tunnel #' + this.tunnel.index + ' WebSocket control close');
703 + //sendConsoleText('Tunnel #' + this.tunnel.index + ' WebSocket control close');
704 try { this.close(); } catch (e) { }
705 + } else if (obj.type == 'webrtc0') { // Browser indicates we can start WebRTC switch-over.
706 + if (this.websocket.httprequest.protocol == 1) { // Terminal
707 + // This is a terminal data stream, unpipe the terminal now and indicate to the other side that terminal data will no longer be received over WebSocket
708 + this.websocket.httprequest.process.stdout.unpipe(this.websocket);
709 + this.websocket.httprequest.process.stderr.unpipe(this.websocket);
710 + this.websocket.write("{\"type\":\"webrtc1\"}"); // End of data marker
711 + } else if (this.websocket.httprequest.protocol == 2) { // Desktop
712 + // This is a KVM data stream, unpipe the KVM now and indicate to the other side that KVM data will no longer be received over WebSocket
713 + this.websocket.httprequest.desktop.kvm.unpipe(this.websocket);
714 + this.websocket.write("{\"type\":\"webrtc1\"}"); // End of data marker
715 + }
716 + /*
717 + else {
718 + // Debug, just display on agent console
719 + rtcchannel.on('data', function (buffer) { sendConsoleText("RTCReceived: " + buffer.length + " bytes"); });
720 + rtcchannel.on('end', function () { sendConsoleText("RTCChannel: " + this.name + " was closed"); });
721 + channel.write('WebRTC HELLO!');
722 + }
723 + */
724 } else if (obj.type == 'webrtc1') {
706 - this.write("{\"type\":\"webrtc2\"}"); // Indicates we will no longer get any data on websocket, switching to WebRTC at this point.
725 if (this.httprequest.protocol == 1) { // Terminal
726 // Switch the user input from websocket to webrtc at this point.
727 this.unpipe(this.httprequest.process.stdin);
@@ -712,9 +730,10 @@ function createMeshCore(agent) {
730 } else if (this.httprequest.protocol == 2) { // Desktop
731 // Switch the user input from websocket to webrtc at this point.
732 this.unpipe(this.httprequest.desktop.kvm);
715 - this.webrtc.rtcchannel.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
733 + try { this.webrtc.rtcchannel.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1 }); } catch (e) { sendConsoleText('EX2'); } // 0 = Binary, 1 = Text.
734 this.resume(); // Resume the websocket to keep receiving control data
735 }
736 + this.write("{\"type\":\"webrtc2\"}"); // Indicates we will no longer get any data on websocket, switching to WebRTC at this point.
737 } else if (obj.type == 'webrtc2') {
738 // Other side received websocket end of data marker, start sending data on WebRTC channel
739 if (this.httprequest.protocol == 1) { // Terminal
@@ -727,34 +746,17 @@ function createMeshCore(agent) {
746 // This is a WebRTC offer.
747 this.webrtc = rtc.createConnection();
748 this.webrtc.websocket = this;
730 - this.webrtc.on('connected', function () { sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC connected'); });
731 - this.webrtc.on('disconnected', function () { sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC disconnected'); });
749 + this.webrtc.on('connected', function () { /*sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC connected');*/ });
750 + this.webrtc.on('disconnected', function () { /*sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC disconnected');*/ });
751 this.webrtc.on('dataChannel', function (rtcchannel) {
733 - sendConsoleText('WebRTC Datachannel open, protocol: ' + this.websocket.httprequest.protocol);
752 + //sendConsoleText('WebRTC Datachannel open, protocol: ' + this.websocket.httprequest.protocol);
753 rtcchannel.xrtc = this;
754 rtcchannel.websocket = this.websocket;
755 this.rtcchannel = rtcchannel;
756 this.websocket.rtcchannel = rtcchannel;
757 this.websocket.rtcchannel.on('data', onTunnelWebRTCControlData);
739 - this.websocket.rtcchannel.on('end', function () { sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC data channel closed'); });
740 - if (this.websocket.httprequest.protocol == 1) { // Terminal
741 - // This is a terminal data stream, unpipe the terminal now and indicate to the other side that terminal data will no longer be received over WebSocket
742 - this.websocket.httprequest.process.stdout.unpipe(this.websocket);
743 - this.websocket.httprequest.process.stderr.unpipe(this.websocket);
744 - this.websocket.write("{\"type\":\"webrtc1\"}"); // End of data marker
745 - } else if (this.websocket.httprequest.protocol == 2) { // Desktop
746 - // This is a KVM data stream, unpipe the KVM now and indicate to the other side that KVM data will no longer be received over WebSocket
747 - this.websocket.httprequest.desktop.kvm.unpipe(this.websocket);
748 - this.websocket.write("{\"type\":\"webrtc1\"}"); // End of data marker
749 - }
750 - /*
751 - else {
752 - // Debug, just display on agent console
753 - rtcchannel.on('data', function (buffer) { sendConsoleText("RTCReceived: " + buffer.length + " bytes"); });
754 - rtcchannel.on('end', function () { sendConsoleText("RTCChannel: " + this.name + " was closed"); });
755 - channel.write('WebRTC HELLO!');
756 - }
757 - */
758 + this.websocket.rtcchannel.on('end', function () { /*sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC data channel closed');*/ });
759 + this.websocket.write("{\"type\":\"webrtc0\"}"); // Indicate we are ready for WebRTC switch-over.
760 });
761 this.write({ type: "answer", sdp: this.webrtc.setOffer(obj.sdp) });
762 }
agents/meshinstall-linux.sh
+1 -1
@@ -87,7 +87,7 @@ DownloadAgent() {
87 UpdateMshFile
88 if [ $starttype -eq 1 ]
89 then
90 - echo -e "[Unit]\nDescription=MeshCentral Agent\n[Service]\nExecStart=/usr/local/mesh/meshagent\nStandardOutput=null\n[Install]\nWantedBy=multi-user.target\nAlias=meshagent.service\n" > /lib/systemd/system/meshagent.service
90 + echo -e "[Unit]\nDescription=MeshCentral Agent\n[Service]\nExecStart=/usr/local/mesh/meshagent\nStandardOutput=null\nRestart=always\nRestartSec=3\n[Install]\nWantedBy=multi-user.target\nAlias=meshagent.service\n" > /lib/systemd/system/meshagent.service
91 systemctl enable meshagent
92 systemctl start meshagent
93 else
interceptor.js
+3
@@ -22,6 +22,7 @@ module.exports.CreateHttpInterceptor = function (args) {
22 obj.args = args;
23 obj.amt = { acc: "", mode: 0, count: 0, error: false }; // mode: 0:Header, 1:LengthBody, 2:ChunkedBody, 3:UntilClose
24 obj.ws = { acc: "", mode: 0, count: 0, error: false, authCNonce: obj.randomValueHex(10), authCNonceCount: 1 };
25 + obj.blockAmtStorage = false;
26
27 // Private method
28 obj.Debug = function (msg) { console.log(msg); }
@@ -131,6 +132,8 @@ module.exports.CreateHttpInterceptor = function (args) {
132 var headerlines = obj.ws.acc.substring(0, headerend).split('\r\n');
133 obj.ws.acc = obj.ws.acc.substring(headerend + 4);
134 obj.ws.directive = headerlines[0].split(' ');
135 + // If required, block access to amt-storage. This is needed when web storage is not supported on CIRA.
136 + if ((obj.blockAmtStorage == true) && (obj.ws.directive.length > 1) && (obj.ws.directive[1].indexOf('/amt-storage') == 0)) { obj.ws.directive[1] = obj.ws.directive[1].replace('/amt-storage', '/amt-dummy-storage'); }
137 var headers = headerlines.slice(1);
138 obj.ws.headers = {};
139 obj.ws.mode = 3; // UntilClose
meshagent.js
+1 -1
@@ -442,7 +442,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
442 if (rights != null) { // TODO: Look at what rights are needed for message routing
443 var sessions = obj.parent.wssessions[userid];
444 // Send the message to all users on this server
445 - for (var i in sessions) { sessions[i].send(cmdstr); }
445 + for (var i in sessions) { try { sessions[i].send(cmdstr); } catch (e) { } }
446 }
447 }
448 }
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.1.3-x",
3 + "version": "0.1.4-b",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
public/scripts/agent-desktop-0.0.2.js
+8 -1
@@ -173,12 +173,18 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
173 }
174
175 obj.ProcessData = function (str) {
176 + var ptr = 0;
177 + while (ptr < str.length) { ptr += obj.ProcessDataEx(str.substring(ptr)); }
178 + }
179 +
180 + obj.ProcessDataEx = function (str) {
181 if (str.length < 4) return;
182 var cmdmsg = null, X = 0, Y = 0, command = ReadShort(str, 0), cmdsize = ReadShort(str, 2);
183 + if ((cmdsize != str.length) && (obj.debugmode == 1)) { console.log(cmdsize, str.length, cmdsize == str.length); }
184 if (command >= 18) { console.error("Invalid KVM command " + command + " of size " + cmdsize); console.log("Invalid KVM data", str.length, str, rstr2hex(str)); return; }
185 if (cmdsize > str.length) { console.error("KVM invalid command size", cmdsize, str.length); return; }
186 //meshOnDebug("KVM Command: " + command + " Len:" + cmdsize);
181 - if (obj.debugmode == 1) { console.log("KVM Command: " + command + " Len:" + cmdsize); }
187 + //if (obj.debugmode == 1) { console.log("KVM Command: " + command + " Len:" + cmdsize); }
188
189 if (command == 3 || command == 4 || command == 7) {
190 cmdmsg = str.substring(4, cmdsize);
@@ -244,6 +250,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
250 if (obj.onMessage != null) obj.onMessage(str.substring(4, cmdsize), obj);
251 break;
252 }
253 + return cmdsize;
254 }
255
256 // Keyboard and Mouse I/O.
public/scripts/agent-redir-ws-0.1.0.js
+14 -7
@@ -18,6 +18,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
18 obj.protocol = module.protocol; // 1 = SOL, 2 = KVM, 3 = IDER, 4 = Files, 5 = FileTransfer
19 obj.attemptWebRTC = false;
20 obj.webRtcActive = false;
21 + obj.webSwitchOk = false;
22 obj.webrtc = null;
23 obj.webchannel = null;
24 obj.onStateChanged = null;
@@ -56,6 +57,9 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
57 if (obj.webrtc != null) {
58 if (controlMsg.type == 'answer') {
59 obj.webrtc.setRemoteDescription(new RTCSessionDescription(controlMsg), function () { /*console.log('WebRTC remote ok');*/ }, obj.xxCloseWebRTC);
60 + } else if (controlMsg.type == 'webrtc0') {
61 + obj.webSwitchOk = true; // Other side is ready for switch over
62 + performWebRtcSwitch();
63 } else if (controlMsg.type == 'webrtc1') {
64 obj.socket.send("{\"type\":\"webrtc2\"}"); // Confirm we got end of data marker, indicates data will no longer be received on websocket.
65 } else if (controlMsg.type == 'webrtc2') {
@@ -64,6 +68,14 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
68 }
69 }
70
71 + function performWebRtcSwitch() {
72 + if ((obj.webSwitchOk == true) && (obj.webRtcActive == true)) {
73 + obj.socket.send("{\"type\":\"webrtc1\"}"); // Indicate to the other side that data traffic will no longer be sent over websocket.
74 + // TODO: Hold/Stop sending data over websocket
75 + if (obj.onStateChanged != null) { obj.onStateChanged(obj, obj.State); }
76 + }
77 + }
78 +
79 // Close the WebRTC connection, should be called if a problem occurs during WebRTC setup.
80 obj.xxCloseWebRTC = function () {
81 try { obj.webchannel.send("{\"type\":\"close\"}"); } catch (e) { }
@@ -84,15 +96,12 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
96 var configuration = null; //{ "iceServers": [ { 'urls': 'stun:stun.services.mozilla.com' }, { 'urls': 'stun:stun.l.google.com:19302' } ] };
97 if (typeof RTCPeerConnection !== 'undefined') { obj.webrtc = new RTCPeerConnection(configuration); }
98 else if (typeof webkitRTCPeerConnection !== 'undefined') { obj.webrtc = new webkitRTCPeerConnection(configuration); }
87 -
99 if (obj.webrtc != null) {
100 obj.webchannel = obj.webrtc.createDataChannel("DataChannel", {}); // { ordered: false, maxRetransmits: 2 }
101 obj.webchannel.onmessage = function (event) { obj.xxOnMessage({ data: event.data }); };
102 obj.webchannel.onopen = function () {
103 obj.webRtcActive = true;
93 - obj.socket.send("{\"type\":\"webrtc1\"}"); // Indicate to the other side that data traffic will no longer be sent over websocket.
94 - // TODO: Hold/Stop sending data over websocket
95 - if (obj.onStateChanged != null) { obj.onStateChanged(obj, obj.State); }
104 + performWebRtcSwitch();
105 };
106 obj.webchannel.onclose = function (event) { /*console.log('WebRTC close');*/ obj.Stop(); }
107 obj.webrtc.onicecandidate = function (e) {
@@ -104,7 +113,6 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
113 }
114 obj.webrtc.oniceconnectionstatechange = function () {
115 if (obj.webrtc != null) {
107 - //console.log(obj.webrtc.iceConnectionState)
116 if ((obj.webrtc.iceConnectionState == 'disconnected') || (obj.webrtc.iceConnectionState == 'failed')) { obj.xxCloseWebRTC(); }
117 }
118 }
@@ -205,8 +213,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
213 obj.connectstate = -1;
214 obj.xxCloseWebRTC();
215 if (obj.socket != null) {
208 - try { obj.socket.send("{\"type\":\"close\"}"); } catch (e) { }
209 - try { obj.socket.close(); } catch (e) { }
216 + try { if (obj.socket.readyState == 1) { obj.socket.send("{\"type\":\"close\"}"); obj.socket.close(); } } catch (e) { }
217 obj.socket = null;
218 }
219 obj.xxStateChange(0);
views/default.handlebars
+2 -2
@@ -650,7 +650,7 @@
650 var amtScanResults = null;
651 var debugmode = false;
652 var clickOnce = detectClickOnce();
653 - var attemptWebRTC = false;
653 + var attemptWebRTC = true;
654
655 function startup() {
656 if ((features & 32) == 0) {
@@ -663,7 +663,7 @@
663 // Check if we are in debug mode
664 args = parseUriArgs();
665 debugmode = (args.debug == 1);
666 - attemptWebRTC = (args.webrtc == 1);
666 + //attemptWebRTC = (args.webrtc == 1);
667 QV('p13AutoConnect', debugmode); // Files
668 QV('autoconnectbutton2', debugmode); // Terminal
669 QV('autoconnectbutton1', debugmode); // Desktop
webserver.js
+2
@@ -1132,10 +1132,12 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
1132 if (req.query.p == 1) {
1133 Debug(3, 'INTERCEPTOR1', { host: node.host, port: port, user: node.intelamt.user, pass: node.intelamt.pass });
1134 ws.interceptor = obj.interceptor.CreateHttpInterceptor({ host: node.host, port: port, user: node.intelamt.user, pass: node.intelamt.pass });
1135 + ws.interceptor.blockAmtStorage = true;
1136 }
1137 else if (req.query.p == 2) {
1138 Debug(3, 'INTERCEPTOR2', { user: node.intelamt.user, pass: node.intelamt.pass });
1139 ws.interceptor = obj.interceptor.CreateRedirInterceptor({ user: node.intelamt.user, pass: node.intelamt.pass });
1140 + ws.interceptor.blockAmtStorage = true;
1141 }
1142
1143 return;