mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-03-09 15:40:18 +00:00
Added support for MeshCmd routing.
This commit is contained in:
parent
951e6236f9
commit
e75adafb05
21 changed files with 343 additions and 70 deletions
BIN
agents/MeshConsole.exe
Normal file
BIN
agents/MeshConsole.exe
Normal file
Binary file not shown.
BIN
agents/MeshConsole64.exe
Normal file
BIN
agents/MeshConsole64.exe
Normal file
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.
Binary file not shown.
170
agents/meshcmd.js
Normal file
170
agents/meshcmd.js
Normal file
|
@ -0,0 +1,170 @@
|
|||
var fs = require('fs');
|
||||
var os = require('os');
|
||||
var net = require('net');
|
||||
var http = require('http');
|
||||
var dgram = require('dgram');
|
||||
var httpHeaders = require('http-headers');
|
||||
var tcpserver = null;
|
||||
var broadcastSockets = {};
|
||||
var multicastSockets = {};
|
||||
var discoveryInterval = null;
|
||||
var membershipIPv4 = '239.255.255.235';
|
||||
var membershipIPv6 = 'FF02:0:0:0:0:0:0:FE';
|
||||
|
||||
/*
|
||||
// Route Settings
|
||||
var settings = {
|
||||
action: 'route',
|
||||
localPort: 1234,
|
||||
remoteName: 'AmtMachine7',
|
||||
remoteNodeId: 'node//nmiPnDhT3vHKu$zg296YC5RjK53Trgh3Cimx3K8GVrFh$xch0UAAett2rbJpeddc',
|
||||
remotePort: 3389,
|
||||
username: 'a',
|
||||
password: 'a',
|
||||
serverUrl: 'wss://devbox.mesh.meshcentral.com:443/meshrelay.ashx',
|
||||
serverId: 'D99362D5ED8BAEA8BF9E743B34B242256370C460FD66CB62373C6CFCB204D6D707403E396CF0EF6DC2B3A42F735135FD', // SHA384 of server HTTPS public key
|
||||
serverHttpsHash: 'D9DE9E27A229B5355708A3672FB23237CC994A680B3570D242A91E36B4AE5BC9', // SHA256 of server HTTPS certificate
|
||||
debugLevel: 0
|
||||
}
|
||||
*/
|
||||
|
||||
// Check the server certificate fingerprint
|
||||
function onVerifyServer(clientName, certs) {
|
||||
try { for (var i in certs) { if (certs[i].fingerprint.replace(/:/g, '') == settings.serverHttpsHash) { return; } } } catch (e) { }
|
||||
if (serverhash != null) { console.log('Error: Failed to verify server certificate.'); return false; }
|
||||
}
|
||||
|
||||
// Print a debug message
|
||||
function debug(level, message) { if ((settings.debugLevel != null) && (settings.debugLevel >= level)) { console.log(message); } }
|
||||
|
||||
// Start the router, start by listening to the local port
|
||||
function run(argv) {
|
||||
console.log('MeshCentral Command v1.0');
|
||||
var actionpath = 'meshaction.txt';
|
||||
if (argv.length >= 2) { actionpath = argv[1]; }
|
||||
|
||||
// Load the action file
|
||||
var actionfile = null;
|
||||
try { actionfile = fs.readFileSync(actionpath); } catch (e) { }
|
||||
if (actionfile == null) { console.log('Unable to load \"' + actionpath + '\". Create this file or specify the location as the first argument.'); process.exit(1); }
|
||||
try { settings = JSON.parse(actionfile); } catch (e) { console.log(actionpath, e); process.exit(1); }
|
||||
|
||||
// Validate meshaction.txt
|
||||
if (settings.action == null) { console.log('No \"action\" specified.'); process.exit(1); }
|
||||
settings.action = settings.action.toLowerCase();
|
||||
if (settings.action == 'route') {
|
||||
if ((settings.localPort == null) || (typeof settings.localPort != 'number') || (settings.localPort < 0) || (settings.localPort > 65535)) { console.log('No or invalid \"localPort\" specified.'); process.exit(1); }
|
||||
if ((settings.remoteNodeId == null) || (typeof settings.remoteNodeId != 'string')) { console.log('No or invalid \"remoteNodeId\" specified.'); process.exit(1); }
|
||||
if ((settings.username == null) || (typeof settings.username != 'string')) { console.log('No or invalid \"username\" specified.'); process.exit(1); }
|
||||
if ((settings.password == null) || (typeof settings.password != 'string') || (settings.password == '')) { console.log('No or invalid \"password\" specified.'); process.exit(1); }
|
||||
if ((settings.serverId == null) || (typeof settings.serverId != 'string') || (settings.serverId.length != 96)) { console.log('No or invalid \"serverId\" specified.'); process.exit(1); }
|
||||
if ((settings.serverHttpsHash == null) || (typeof settings.serverHttpsHash != 'string') || (settings.serverHttpsHash.length != 96)) { console.log('No or invalid \"serverHttpsHash\" specified.'); process.exit(1); }
|
||||
if ((settings.remotePort == null) || (typeof settings.remotePort != 'number') || (settings.remotePort < 0) || (settings.remotePort > 65535)) { console.log('No or invalid \"remotePort\" specified.'); process.exit(1); }
|
||||
} else {
|
||||
console.log('Invalid \"action\" specified.'); process.exit(1);
|
||||
}
|
||||
|
||||
debug(1, "Settings: " + JSON.stringify(settings));
|
||||
if (settings.serverUrl != null) { startRouter(); } else { discoverMeshServer(); }
|
||||
}
|
||||
|
||||
// Starts the router
|
||||
function startRouter() {
|
||||
tcpserver = net.createServer(OnTcpClientConnected);
|
||||
tcpserver.on('error', function (err) { console.log(err); process.exit(0); });
|
||||
tcpserver.listen(settings.localPort, function () {
|
||||
// We started listening.
|
||||
if (settings.remoteName == null) {
|
||||
console.log('Redirecting local port ' + settings.localPort + ' to remote port ' + settings.remotePort + '.');
|
||||
} else {
|
||||
console.log('Redirecting local port ' + settings.localPort + ' to ' + settings.remoteName + ':' + settings.remotePort + '.');
|
||||
}
|
||||
console.log('Press ctrl-c to terminal.');
|
||||
|
||||
// If settings has a "cmd", run it now.
|
||||
//process.exec("notepad.exe");
|
||||
});
|
||||
}
|
||||
|
||||
// Called when a TCP connect is received on the local port. Launch a tunnel.
|
||||
function OnTcpClientConnected(c) {
|
||||
try {
|
||||
// 'connection' listener
|
||||
debug(1, 'Client connected');
|
||||
c.on('end', function () { disconnectTunnel(this, this.websocket, 'Client closed'); });
|
||||
c.pause();
|
||||
|
||||
try {
|
||||
options = http.parseUri(settings.serverUrl + '?user=' + settings.username + '&pass=' + settings.password + '&nodeid=' + settings.remoteNodeId + '&tcpport=' + settings.remotePort);
|
||||
} catch (e) { console.log('Unable to parse \"serverUrl\".'); process.exit(1); }
|
||||
options.checkServerIdentity = onVerifyServer;
|
||||
c.websocket = http.request(options);
|
||||
c.websocket.tcp = c;
|
||||
c.websocket.tunneling = false;
|
||||
c.websocket.upgrade = OnWebSocket;
|
||||
c.websocket.on('error', function (msg) { console.log(msg); });
|
||||
c.websocket.end();
|
||||
} catch (e) { debug(2, e); }
|
||||
}
|
||||
|
||||
// Disconnect both TCP & WebSocket connections and display a message.
|
||||
function disconnectTunnel(tcp, ws, msg) {
|
||||
if (ws != null) { try { ws.end(); } catch (e) { debug(2, e); } }
|
||||
if (tcp != null) { try { tcp.end(); } catch (e) { debug(2, e); } }
|
||||
debug(1, 'Tunnel disconnected: ' + msg);
|
||||
}
|
||||
|
||||
// Called when the web socket gets connected
|
||||
function OnWebSocket(msg, s, head) {
|
||||
debug(1, 'Websocket connected');
|
||||
s.on('data', function (msg) {
|
||||
if (this.parent.tunneling == false) {
|
||||
msg = msg.toString();
|
||||
if (msg == 'c') {
|
||||
this.parent.tunneling = true; this.pipe(this.parent.tcp); this.parent.tcp.pipe(this); debug(1, 'Tunnel active');
|
||||
} else if ((msg.length > 6) && (msg.substring(0, 6) == 'error:')) {
|
||||
console.log(msg.substring(6));
|
||||
disconnectTunnel(this.tcp, this, msg.substring(6));
|
||||
}
|
||||
}
|
||||
});
|
||||
s.on('error', function (msg) { disconnectTunnel(this.tcp, this, 'Websocket error'); });
|
||||
s.on('close', function (msg) { disconnectTunnel(this.tcp, this, 'Websocket closed'); });
|
||||
s.parent = this;
|
||||
}
|
||||
|
||||
// Try to discover the location of the mesh server
|
||||
function discoverMeshServer() { console.log('Looking for server...'); discoveryInterval = setInterval(discoverMeshServerOnce, 5000); discoverMeshServerOnce(); }
|
||||
|
||||
// Try to discover the location of the mesh server only once
|
||||
function discoverMeshServerOnce() {
|
||||
var interfaces = os.networkInterfaces();
|
||||
for (var adapter in interfaces) {
|
||||
if (interfaces.hasOwnProperty(adapter)) {
|
||||
for (var i = 0 ; i < interfaces[adapter].length; ++i) {
|
||||
var addr = interfaces[adapter][i];
|
||||
multicastSockets[i] = dgram.createSocket({ type: (addr.family == "IPv4" ? "udp4" : "udp6") });
|
||||
multicastSockets[i].bind({ address: addr.address, exclusive: false });
|
||||
if (addr.family == "IPv4") {
|
||||
multicastSockets[i].addMembership(membershipIPv4);
|
||||
//multicastSockets[i].setMulticastLoopback(true);
|
||||
multicastSockets[i].once('message', OnMulticastMessage);
|
||||
multicastSockets[i].send(settings.serverId, 16989, membershipIPv4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called when a multicast packet is received
|
||||
function OnMulticastMessage(msg, rinfo) {
|
||||
var m = msg.toString().split('|');
|
||||
if ((m.length == 3) && (m[0] == 'MeshCentral2') && (m[1] == settings.serverId)) {
|
||||
settings.serverUrl = m[2].replace('%s', rinfo.address).replace('/agent.ashx', '/meshrelay.ashx');
|
||||
console.log('Found server at ' + settings.serverUrl + '.');
|
||||
if (discoveryInterval != null) { clearInterval(discoveryInterval); discoveryInterval = null; }
|
||||
startRouter();
|
||||
}
|
||||
}
|
||||
|
||||
try { run(process.argv); } catch (e) { /*console.log(e);*/ }
|
|
@ -59,7 +59,7 @@ CheckInstallAgent() {
|
|||
DownloadAgent $url $meshid $machineid
|
||||
fi
|
||||
else
|
||||
echo "MeshID is not correct, must be 64 HEX characters long."
|
||||
echo "MeshID is not correct, must be 64 characters long."
|
||||
fi
|
||||
else
|
||||
echo "URI and/or MeshID have not been specified, must be passed in as arguments."
|
||||
|
@ -78,7 +78,7 @@ DownloadAgent() {
|
|||
wget $url/meshagents?id=$machineid -q --no-check-certificate -O /usr/local/mesh/meshagent
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
echo "Mesh agent download."
|
||||
echo "Mesh agent downloaded."
|
||||
# TODO: We could check the meshagent sha256 hash, but best to authenticate the server.
|
||||
chmod 755 /usr/local/mesh/meshagent
|
||||
wget $url/meshsettings?id=$meshid -q --no-check-certificate -O /usr/local/mesh/meshagent.msh
|
||||
|
@ -97,6 +97,7 @@ DownloadAgent() {
|
|||
ln -s /usr/local/mesh/meshagent /etc/rc3.d/S20mesh
|
||||
ln -s /usr/local/mesh/meshagent /etc/rc5.d/S20mesh
|
||||
fi
|
||||
echo "Mesh agent started."
|
||||
else
|
||||
echo "Unable to download mesh settings at: $url/meshsettings?id=$meshid."
|
||||
fi
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue