From 8be7984a60a8feb8e3919e960ff353ba95a50d7c Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Fri, 17 Jul 2020 19:55:49 -0700 Subject: [PATCH] More agent deflate compression support. --- agents/meshcore.js | 45 +++++++++++++++++++++------------- meshagent.js | 13 +++++----- meshcentral-config-schema.json | 3 ++- meshuser.js | 3 +++ sample-config-advanced.json | 4 ++- 5 files changed, 42 insertions(+), 26 deletions(-) diff --git a/agents/meshcore.js b/agents/meshcore.js index 187a1135..17a359a6 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -643,6 +643,7 @@ function createMeshCore(agent) { // Send a wake-on-lan packet function sendWakeOnLan(hexMac) { + hexMac = hexMac.split(':').join(''); var count = 0; try { var interfaces = require('os').networkInterfaces(); @@ -650,17 +651,12 @@ function createMeshCore(agent) { for (var x = 1; x <= 16; ++x) { magic += hexMac; } var magicbin = Buffer.from(magic, 'hex'); - for (var adapter in interfaces) - { - if (interfaces.hasOwnProperty(adapter)) - { - for (var i = 0; i < interfaces[adapter].length; ++i) - { + for (var adapter in interfaces) { + if (interfaces.hasOwnProperty(adapter)) { + for (var i = 0; i < interfaces[adapter].length; ++i) { var addr = interfaces[adapter][i]; - if ((addr.family == 'IPv4') && (addr.mac != '00:00:00:00:00:00')) - { - try - { + if ((addr.family == 'IPv4') && (addr.mac != '00:00:00:00:00:00')) { + try { var socket = require('dgram').createSocket({ type: 'udp4' }); socket.bind({ address: addr.address }); socket.setBroadcast(true); @@ -668,14 +664,12 @@ function createMeshCore(agent) { socket.descriptorMetadata = 'WoL (' + addr.address + ' => ' + hexMac + ')'; count++; } - catch(ee) - { - } + catch (ex) { } } } } } - } catch (e) { } + } catch (ex) { } return count; } @@ -701,7 +695,8 @@ function createMeshCore(agent) { if (xurl != null) { xurl = xurl.split('$').join('%24').split('@').join('%40'); // Escape the $ and @ characters var woptions = http.parseUri(xurl); - woptions.perMessageDeflate = true; + woptions.perMessageDeflate = false; + if (typeof data.perMessageDeflate == 'boolean') { woptions.perMessageDeflate = data.perMessageDeflate; } woptions.rejectUnauthorized = 0; //sendConsoleText(JSON.stringify(woptions)); //sendConsoleText('TUNNEL: ' + JSON.stringify(data)); @@ -1188,9 +1183,25 @@ function createMeshCore(agent) { } function onTunnelClosed() { - if (tunnels[this.httprequest.index] == null) return; // Stop duplicate calls. + var tunnel = tunnels[this.httprequest.index]; + if (tunnel == null) return; // Stop duplicate calls. -// sendConsoleText("Tunnel #" + this.httprequest.index + " closed. Sent -> " + this.bytesSent_uncompressed + ' bytes (uncompressed), ' + this.bytesSent_actual + ' bytes (actual), ' + this.bytesSent_ratio + '% compression', this.httprequest.sessionid); + // Sent tunnel statistics to the server + mesh.SendCommand({ + action: 'tunnelCloseStats', + url: tunnel.url, + userid: tunnel.userid, + protocol: tunnel.protocol, + sessionid: tunnel.sessionid, + sent: this.bytesSent_uncompressed + '', + sentActual: this.bytesSent_actual + '', + sentRatio: this.bytesSent_ratio, + received: this.bytesReceived_uncompressed + '', + receivedActual: this.bytesReceived_actual + '', + receivedRatio: this.bytesReceived_ratio + }); + + //sendConsoleText("Tunnel #" + this.httprequest.index + " closed. Sent -> " + this.bytesSent_uncompressed + ' bytes (uncompressed), ' + this.bytesSent_actual + ' bytes (actual), ' + this.bytesSent_ratio + '% compression', this.httprequest.sessionid); delete tunnels[this.httprequest.index]; /* diff --git a/meshagent.js b/meshagent.js index 44aca213..3514106b 100644 --- a/meshagent.js +++ b/meshagent.js @@ -239,7 +239,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { if (obj.authenticated != 2) { parent.parent.taskLimiter.completed(taskid); return; } // If agent disconnection, complete and exit now. if (obj.nodeid != null) { parent.parent.debug('agent', "Agent update required, NodeID=0x" + obj.nodeid.substring(0, 16) + ', ' + obj.agentExeInfo.desc); } parent.agentStats.agentBinaryUpdate++; - if (obj.agentExeInfo.data == null) { + if ((obj.agentExeInfo.data == null) && (((obj.agentInfo.capabilities & 0x80) == 0) || (obj.agentExeInfo.zdata == null))) { // Read the agent from disk parent.fs.open(obj.agentExeInfo.path, 'r', function (err, fd) { if (obj.agentExeInfo == null) return; // Agent disconnected during this call. @@ -292,7 +292,6 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { obj.agentUpdate.buf[2] = 0; obj.agentUpdate.buf[3] = 1; - /* // If agent supports compression, send the compressed agent if possible. if ((obj.agentInfo.capabilities & 0x80) && (obj.agentExeInfo.zdata != null)) { // Send compressed data @@ -305,11 +304,6 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { obj.agentUpdate.agentUpdateHash = obj.agentExeInfo.hash; //console.log('Sending uncompressed update agent', obj.agentExeInfo.hashhex); } - */ - - // Send uncompressed data - obj.agentUpdate.agentUpdateData = obj.agentExeInfo.data; - obj.agentUpdate.agentUpdateHash = obj.agentExeInfo.hash; const len = Math.min(parent.parent.agentUpdateBlockSize, obj.agentUpdate.agentUpdateData.length - obj.agentUpdate.ptr); if (len > 0) { @@ -1418,6 +1412,11 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { } break; } + case 'tunnelCloseStats': { + // TODO: This this extra stats from the tunnel, you can merge this into the tunnel event in the database. + //console.log(command); + break; + } case 'plugin': { if ((parent.parent.pluginHandler == null) || (typeof command.plugin != 'string')) break; try { diff --git a/meshcentral-config-schema.json b/meshcentral-config-schema.json index 3ed7a3da..d074394f 100644 --- a/meshcentral-config-schema.json +++ b/meshcentral-config-schema.json @@ -55,7 +55,8 @@ "agentPong": { "type": "integer", "minimum": 1, "description": "When specified, sends data to the agent at x seconds interval." }, "agentIdleTimeout": { "type": "integer", "minimum": 1 }, "compression": { "type": "boolean", "default": true, "description": "Enables GZIP compression for web requests." }, - "wscompression": { "type": "boolean", "default": false, "description": "Enables websocket per-message deflate compression." }, + "wscompression": { "type": "boolean", "default": false, "description": "Enables server-side, websocket per-message deflate compression." }, + "agentwscompression": { "type": "boolean", "default": true, "description": "Enables agent-side, websocket per-message deflate compression. wscompression must also be true for this to work." }, "meshErrorLogPath": { "type": "string" }, "npmPath": { "type": "string" }, "npmProxy": { "type": "string", "format": "uri" }, diff --git a/meshuser.js b/meshuser.js index 748cc461..8e471fad 100644 --- a/meshuser.js +++ b/meshuser.js @@ -1218,6 +1218,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (typeof domain.notificationmessages.terminal == 'string') { command.soptions.notifyMsgTerminal = domain.notificationmessages.terminal; } if (typeof domain.notificationmessages.files == 'string') { command.soptions.notifyMsgFiles = domain.notificationmessages.files; } } + + // Add tunnel pre-message deflate + if (typeof parent.parent.config.settings.agentwscompression == 'boolean') { command.perMessageDeflate = parent.parent.config.settings.agentwscompression; } } // If a response is needed, set a callback function diff --git a/sample-config-advanced.json b/sample-config-advanced.json index f3b117b6..148f49f9 100644 --- a/sample-config-advanced.json +++ b/sample-config-advanced.json @@ -37,7 +37,9 @@ "_allowFraming": true, "_cookieIpCheck": false, "_cookieEncoding": "hex", - "_compression": false, + "_compression": true, + "_wscompression": false, + "_agentwscompression": true, "_webRTC": false, "_nice404": false, "_clickOnce": false,