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;