mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-12-23 21:55:52 -05:00
WebRTC is now used by default and fully automatic.
This commit is contained in:
parent
c210b926bc
commit
143d4cb647
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -683,7 +683,7 @@ function createMeshCore(agent) {
|
||||
var obj;
|
||||
try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON on WebRTC'); return; }
|
||||
if (obj.type == 'close') {
|
||||
sendConsoleText('Tunnel #' + this.xrtc.websocket.tunnel.index + ' WebRTC control close');
|
||||
//sendConsoleText('Tunnel #' + this.xrtc.websocket.tunnel.index + ' WebRTC control close');
|
||||
try { this.close(); } catch (e) { }
|
||||
try { this.xrtc.close(); } catch (e) { }
|
||||
}
|
||||
@ -692,7 +692,7 @@ function createMeshCore(agent) {
|
||||
// Called when receiving control data on websocket
|
||||
function onTunnelControlData(data) {
|
||||
if (typeof data != 'string') return;
|
||||
sendConsoleText('onTunnelControlData: ' + data);
|
||||
//sendConsoleText('onTunnelControlData: ' + data);
|
||||
//console.log('onTunnelControlData: ' + data);
|
||||
|
||||
var obj;
|
||||
@ -700,10 +700,28 @@ function createMeshCore(agent) {
|
||||
|
||||
if (obj.type == 'close') {
|
||||
// We received the close on the websocket
|
||||
sendConsoleText('Tunnel #' + this.tunnel.index + ' WebSocket control close');
|
||||
//sendConsoleText('Tunnel #' + this.tunnel.index + ' WebSocket control close');
|
||||
try { this.close(); } catch (e) { }
|
||||
} else if (obj.type == 'webrtc0') { // Browser indicates we can start WebRTC switch-over.
|
||||
if (this.websocket.httprequest.protocol == 1) { // Terminal
|
||||
// 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
|
||||
this.websocket.httprequest.process.stdout.unpipe(this.websocket);
|
||||
this.websocket.httprequest.process.stderr.unpipe(this.websocket);
|
||||
this.websocket.write("{\"type\":\"webrtc1\"}"); // End of data marker
|
||||
} else if (this.websocket.httprequest.protocol == 2) { // Desktop
|
||||
// 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
|
||||
this.websocket.httprequest.desktop.kvm.unpipe(this.websocket);
|
||||
this.websocket.write("{\"type\":\"webrtc1\"}"); // End of data marker
|
||||
}
|
||||
/*
|
||||
else {
|
||||
// Debug, just display on agent console
|
||||
rtcchannel.on('data', function (buffer) { sendConsoleText("RTCReceived: " + buffer.length + " bytes"); });
|
||||
rtcchannel.on('end', function () { sendConsoleText("RTCChannel: " + this.name + " was closed"); });
|
||||
channel.write('WebRTC HELLO!');
|
||||
}
|
||||
*/
|
||||
} else if (obj.type == 'webrtc1') {
|
||||
this.write("{\"type\":\"webrtc2\"}"); // Indicates we will no longer get any data on websocket, switching to WebRTC at this point.
|
||||
if (this.httprequest.protocol == 1) { // Terminal
|
||||
// Switch the user input from websocket to webrtc at this point.
|
||||
this.unpipe(this.httprequest.process.stdin);
|
||||
@ -712,9 +730,10 @@ function createMeshCore(agent) {
|
||||
} else if (this.httprequest.protocol == 2) { // Desktop
|
||||
// Switch the user input from websocket to webrtc at this point.
|
||||
this.unpipe(this.httprequest.desktop.kvm);
|
||||
this.webrtc.rtcchannel.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
||||
try { this.webrtc.rtcchannel.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1 }); } catch (e) { sendConsoleText('EX2'); } // 0 = Binary, 1 = Text.
|
||||
this.resume(); // Resume the websocket to keep receiving control data
|
||||
}
|
||||
this.write("{\"type\":\"webrtc2\"}"); // Indicates we will no longer get any data on websocket, switching to WebRTC at this point.
|
||||
} else if (obj.type == 'webrtc2') {
|
||||
// Other side received websocket end of data marker, start sending data on WebRTC channel
|
||||
if (this.httprequest.protocol == 1) { // Terminal
|
||||
@ -727,34 +746,17 @@ function createMeshCore(agent) {
|
||||
// This is a WebRTC offer.
|
||||
this.webrtc = rtc.createConnection();
|
||||
this.webrtc.websocket = this;
|
||||
this.webrtc.on('connected', function () { sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC connected'); });
|
||||
this.webrtc.on('disconnected', function () { sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC disconnected'); });
|
||||
this.webrtc.on('connected', function () { /*sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC connected');*/ });
|
||||
this.webrtc.on('disconnected', function () { /*sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC disconnected');*/ });
|
||||
this.webrtc.on('dataChannel', function (rtcchannel) {
|
||||
sendConsoleText('WebRTC Datachannel open, protocol: ' + this.websocket.httprequest.protocol);
|
||||
//sendConsoleText('WebRTC Datachannel open, protocol: ' + this.websocket.httprequest.protocol);
|
||||
rtcchannel.xrtc = this;
|
||||
rtcchannel.websocket = this.websocket;
|
||||
this.rtcchannel = rtcchannel;
|
||||
this.websocket.rtcchannel = rtcchannel;
|
||||
this.websocket.rtcchannel.on('data', onTunnelWebRTCControlData);
|
||||
this.websocket.rtcchannel.on('end', function () { sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC data channel closed'); });
|
||||
if (this.websocket.httprequest.protocol == 1) { // Terminal
|
||||
// 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
|
||||
this.websocket.httprequest.process.stdout.unpipe(this.websocket);
|
||||
this.websocket.httprequest.process.stderr.unpipe(this.websocket);
|
||||
this.websocket.write("{\"type\":\"webrtc1\"}"); // End of data marker
|
||||
} else if (this.websocket.httprequest.protocol == 2) { // Desktop
|
||||
// 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
|
||||
this.websocket.httprequest.desktop.kvm.unpipe(this.websocket);
|
||||
this.websocket.write("{\"type\":\"webrtc1\"}"); // End of data marker
|
||||
}
|
||||
/*
|
||||
else {
|
||||
// Debug, just display on agent console
|
||||
rtcchannel.on('data', function (buffer) { sendConsoleText("RTCReceived: " + buffer.length + " bytes"); });
|
||||
rtcchannel.on('end', function () { sendConsoleText("RTCChannel: " + this.name + " was closed"); });
|
||||
channel.write('WebRTC HELLO!');
|
||||
}
|
||||
*/
|
||||
this.websocket.rtcchannel.on('end', function () { /*sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC data channel closed');*/ });
|
||||
this.websocket.write("{\"type\":\"webrtc0\"}"); // Indicate we are ready for WebRTC switch-over.
|
||||
});
|
||||
this.write({ type: "answer", sdp: this.webrtc.setOffer(obj.sdp) });
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ DownloadAgent() {
|
||||
UpdateMshFile
|
||||
if [ $starttype -eq 1 ]
|
||||
then
|
||||
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
|
||||
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
|
||||
systemctl enable meshagent
|
||||
systemctl start meshagent
|
||||
else
|
||||
|
@ -22,6 +22,7 @@ module.exports.CreateHttpInterceptor = function (args) {
|
||||
obj.args = args;
|
||||
obj.amt = { acc: "", mode: 0, count: 0, error: false }; // mode: 0:Header, 1:LengthBody, 2:ChunkedBody, 3:UntilClose
|
||||
obj.ws = { acc: "", mode: 0, count: 0, error: false, authCNonce: obj.randomValueHex(10), authCNonceCount: 1 };
|
||||
obj.blockAmtStorage = false;
|
||||
|
||||
// Private method
|
||||
obj.Debug = function (msg) { console.log(msg); }
|
||||
@ -131,6 +132,8 @@ module.exports.CreateHttpInterceptor = function (args) {
|
||||
var headerlines = obj.ws.acc.substring(0, headerend).split('\r\n');
|
||||
obj.ws.acc = obj.ws.acc.substring(headerend + 4);
|
||||
obj.ws.directive = headerlines[0].split(' ');
|
||||
// If required, block access to amt-storage. This is needed when web storage is not supported on CIRA.
|
||||
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'); }
|
||||
var headers = headerlines.slice(1);
|
||||
obj.ws.headers = {};
|
||||
obj.ws.mode = 3; // UntilClose
|
||||
|
@ -442,7 +442,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
if (rights != null) { // TODO: Look at what rights are needed for message routing
|
||||
var sessions = obj.parent.wssessions[userid];
|
||||
// Send the message to all users on this server
|
||||
for (var i in sessions) { sessions[i].send(cmdstr); }
|
||||
for (var i in sessions) { try { sessions[i].send(cmdstr); } catch (e) { } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "meshcentral",
|
||||
"version": "0.1.3-x",
|
||||
"version": "0.1.4-b",
|
||||
"keywords": [
|
||||
"Remote Management",
|
||||
"Intel AMT",
|
||||
|
@ -173,12 +173,18 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
|
||||
}
|
||||
|
||||
obj.ProcessData = function (str) {
|
||||
var ptr = 0;
|
||||
while (ptr < str.length) { ptr += obj.ProcessDataEx(str.substring(ptr)); }
|
||||
}
|
||||
|
||||
obj.ProcessDataEx = function (str) {
|
||||
if (str.length < 4) return;
|
||||
var cmdmsg = null, X = 0, Y = 0, command = ReadShort(str, 0), cmdsize = ReadShort(str, 2);
|
||||
if ((cmdsize != str.length) && (obj.debugmode == 1)) { console.log(cmdsize, str.length, cmdsize == str.length); }
|
||||
if (command >= 18) { console.error("Invalid KVM command " + command + " of size " + cmdsize); console.log("Invalid KVM data", str.length, str, rstr2hex(str)); return; }
|
||||
if (cmdsize > str.length) { console.error("KVM invalid command size", cmdsize, str.length); return; }
|
||||
//meshOnDebug("KVM Command: " + command + " Len:" + cmdsize);
|
||||
if (obj.debugmode == 1) { console.log("KVM Command: " + command + " Len:" + cmdsize); }
|
||||
//if (obj.debugmode == 1) { console.log("KVM Command: " + command + " Len:" + cmdsize); }
|
||||
|
||||
if (command == 3 || command == 4 || command == 7) {
|
||||
cmdmsg = str.substring(4, cmdsize);
|
||||
@ -244,6 +250,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
|
||||
if (obj.onMessage != null) obj.onMessage(str.substring(4, cmdsize), obj);
|
||||
break;
|
||||
}
|
||||
return cmdsize;
|
||||
}
|
||||
|
||||
// Keyboard and Mouse I/O.
|
||||
|
@ -18,6 +18,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
|
||||
obj.protocol = module.protocol; // 1 = SOL, 2 = KVM, 3 = IDER, 4 = Files, 5 = FileTransfer
|
||||
obj.attemptWebRTC = false;
|
||||
obj.webRtcActive = false;
|
||||
obj.webSwitchOk = false;
|
||||
obj.webrtc = null;
|
||||
obj.webchannel = null;
|
||||
obj.onStateChanged = null;
|
||||
@ -56,6 +57,9 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
|
||||
if (obj.webrtc != null) {
|
||||
if (controlMsg.type == 'answer') {
|
||||
obj.webrtc.setRemoteDescription(new RTCSessionDescription(controlMsg), function () { /*console.log('WebRTC remote ok');*/ }, obj.xxCloseWebRTC);
|
||||
} else if (controlMsg.type == 'webrtc0') {
|
||||
obj.webSwitchOk = true; // Other side is ready for switch over
|
||||
performWebRtcSwitch();
|
||||
} else if (controlMsg.type == 'webrtc1') {
|
||||
obj.socket.send("{\"type\":\"webrtc2\"}"); // Confirm we got end of data marker, indicates data will no longer be received on websocket.
|
||||
} else if (controlMsg.type == 'webrtc2') {
|
||||
@ -64,6 +68,14 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
|
||||
}
|
||||
}
|
||||
|
||||
function performWebRtcSwitch() {
|
||||
if ((obj.webSwitchOk == true) && (obj.webRtcActive == true)) {
|
||||
obj.socket.send("{\"type\":\"webrtc1\"}"); // Indicate to the other side that data traffic will no longer be sent over websocket.
|
||||
// TODO: Hold/Stop sending data over websocket
|
||||
if (obj.onStateChanged != null) { obj.onStateChanged(obj, obj.State); }
|
||||
}
|
||||
}
|
||||
|
||||
// Close the WebRTC connection, should be called if a problem occurs during WebRTC setup.
|
||||
obj.xxCloseWebRTC = function () {
|
||||
try { obj.webchannel.send("{\"type\":\"close\"}"); } catch (e) { }
|
||||
@ -84,15 +96,12 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
|
||||
var configuration = null; //{ "iceServers": [ { 'urls': 'stun:stun.services.mozilla.com' }, { 'urls': 'stun:stun.l.google.com:19302' } ] };
|
||||
if (typeof RTCPeerConnection !== 'undefined') { obj.webrtc = new RTCPeerConnection(configuration); }
|
||||
else if (typeof webkitRTCPeerConnection !== 'undefined') { obj.webrtc = new webkitRTCPeerConnection(configuration); }
|
||||
|
||||
if (obj.webrtc != null) {
|
||||
obj.webchannel = obj.webrtc.createDataChannel("DataChannel", {}); // { ordered: false, maxRetransmits: 2 }
|
||||
obj.webchannel.onmessage = function (event) { obj.xxOnMessage({ data: event.data }); };
|
||||
obj.webchannel.onopen = function () {
|
||||
obj.webRtcActive = true;
|
||||
obj.socket.send("{\"type\":\"webrtc1\"}"); // Indicate to the other side that data traffic will no longer be sent over websocket.
|
||||
// TODO: Hold/Stop sending data over websocket
|
||||
if (obj.onStateChanged != null) { obj.onStateChanged(obj, obj.State); }
|
||||
performWebRtcSwitch();
|
||||
};
|
||||
obj.webchannel.onclose = function (event) { /*console.log('WebRTC close');*/ obj.Stop(); }
|
||||
obj.webrtc.onicecandidate = function (e) {
|
||||
@ -104,7 +113,6 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
|
||||
}
|
||||
obj.webrtc.oniceconnectionstatechange = function () {
|
||||
if (obj.webrtc != null) {
|
||||
//console.log(obj.webrtc.iceConnectionState)
|
||||
if ((obj.webrtc.iceConnectionState == 'disconnected') || (obj.webrtc.iceConnectionState == 'failed')) { obj.xxCloseWebRTC(); }
|
||||
}
|
||||
}
|
||||
@ -205,8 +213,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
|
||||
obj.connectstate = -1;
|
||||
obj.xxCloseWebRTC();
|
||||
if (obj.socket != null) {
|
||||
try { obj.socket.send("{\"type\":\"close\"}"); } catch (e) { }
|
||||
try { obj.socket.close(); } catch (e) { }
|
||||
try { if (obj.socket.readyState == 1) { obj.socket.send("{\"type\":\"close\"}"); obj.socket.close(); } } catch (e) { }
|
||||
obj.socket = null;
|
||||
}
|
||||
obj.xxStateChange(0);
|
||||
|
@ -650,7 +650,7 @@
|
||||
var amtScanResults = null;
|
||||
var debugmode = false;
|
||||
var clickOnce = detectClickOnce();
|
||||
var attemptWebRTC = false;
|
||||
var attemptWebRTC = true;
|
||||
|
||||
function startup() {
|
||||
if ((features & 32) == 0) {
|
||||
@ -663,7 +663,7 @@
|
||||
// Check if we are in debug mode
|
||||
args = parseUriArgs();
|
||||
debugmode = (args.debug == 1);
|
||||
attemptWebRTC = (args.webrtc == 1);
|
||||
//attemptWebRTC = (args.webrtc == 1);
|
||||
QV('p13AutoConnect', debugmode); // Files
|
||||
QV('autoconnectbutton2', debugmode); // Terminal
|
||||
QV('autoconnectbutton1', debugmode); // Desktop
|
||||
|
@ -1132,10 +1132,12 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||
if (req.query.p == 1) {
|
||||
Debug(3, 'INTERCEPTOR1', { host: node.host, port: port, user: node.intelamt.user, pass: node.intelamt.pass });
|
||||
ws.interceptor = obj.interceptor.CreateHttpInterceptor({ host: node.host, port: port, user: node.intelamt.user, pass: node.intelamt.pass });
|
||||
ws.interceptor.blockAmtStorage = true;
|
||||
}
|
||||
else if (req.query.p == 2) {
|
||||
Debug(3, 'INTERCEPTOR2', { user: node.intelamt.user, pass: node.intelamt.pass });
|
||||
ws.interceptor = obj.interceptor.CreateRedirInterceptor({ user: node.intelamt.user, pass: node.intelamt.pass });
|
||||
ws.interceptor.blockAmtStorage = true;
|
||||
}
|
||||
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user