Started work MeshCentral2 legacy update path.
Ylian Saint-Hilaire committed
Nov 3, 2017 at 17:01 UTC
3a5af0a1c95d597efcdb075f07984aaa29a9f911
5 files changed
+241
-10
MeshCentralServer.njsproj
+1
@@ -35,6 +35,7 @@
35
<Compile Include="meshrelay.js" />
36
<Compile Include="meshuser.js" />
37
<Compile Include="mpsserver.js" />
38
+ <Compile Include="swarmserver.js" />
39
<Compile Include="multiserver.js" />
40
<Compile Include="pass.js" />
41
<Compile Include="public\relay.js" />
certoperations.js
+13
@@ -185,6 +185,19 @@ module.exports.CertificateOperations = function () {
185
rcount++;
186
}
187
188
+ // If the swarm server certificate exist, load it (This is an optional certificate)
189
+ if (obj.fileExists(directory + '/swarmserver-cert-public.crt') && obj.fileExists(directory + '/swarmserver-cert-private.key')) {
190
+ var swarmServerCertificate = obj.fs.readFileSync(directory + '/swarmserver-cert-public.crt', 'utf8');
191
+ var swarmServerPrivateKey = obj.fs.readFileSync(directory + '/swarmserver-cert-private.key', 'utf8');
192
+ r.swarmserver = { cert: swarmServerCertificate, key: swarmServerPrivateKey };
193
+ }
194
+
195
+ // If the swarm server root certificate exist, load it (This is an optional certificate)
196
+ if (obj.fileExists(directory + '/swarmserverroot-cert-public.crt')) {
197
+ var swarmServerRootCertificate = obj.fs.readFileSync(directory + '/swarmserverroot-cert-public.crt', 'utf8');
198
+ r.swarmserverroot = { cert: swarmServerRootCertificate };
199
+ }
200
+
201
// If CA certificates are present, load them
202
var caok, caindex = 1, calist = [];
203
do {
meshcentral.js
+19
-9
@@ -10,6 +10,7 @@ function CreateMeshCentralServer() {
10
obj.webserver;
11
obj.redirserver;
12
obj.mpsserver;
13
+ obj.swarmserver;
14
obj.amtEventHandler;
15
obj.amtScanner;
16
obj.meshScanner;
@@ -64,7 +65,7 @@ function CreateMeshCentralServer() {
65
try { require('./pass').hash('test', function () { }); } catch (e) { console.log('Old version of node, must upgrade.'); return; } // TODO: Not sure if this test works or not.
66
67
// Check for invalid arguments
67
- var validArguments = ['_', 'notls', 'user', 'port', 'mpsport', 'redirport', 'cert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'showiplocations', 'help', 'exactports', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpsdebug', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbimport', 'selfupdate', 'tlsoffload', 'userallowedip', 'fastcert'];
68
+ var validArguments = ['_', 'notls', 'user', 'port', 'mpsport', 'redirport', 'cert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'showiplocations', 'help', 'exactports', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpsdebug', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbimport', 'selfupdate', 'tlsoffload', 'userallowedip', 'fastcert', 'swarmport', 'swarmdebug'];
69
for (var arg in obj.args) { obj.args[arg.toLocaleLowerCase()] = obj.args[arg]; if (validArguments.indexOf(arg.toLocaleLowerCase()) == -1) { console.log('Invalid argument "' + arg + '", use --help.'); return; } }
70
if (obj.args.mongodb == true) { console.log('Must specify: --mongodb [connectionstring] \r\nSee https://docs.mongodb.com/manual/reference/connection-string/ for MongoDB connection string.'); return; }
71
@@ -232,18 +233,21 @@ function CreateMeshCentralServer() {
233
if (obj.args.showiplocations) { obj.db.GetAllType('iploc', function (err, docs) { console.log(docs); process.exit(); }); return; }
234
if (obj.args.dbexport) {
235
// Export the entire database to a JSON file
235
- if (obj.args.dbexport == true) { console.log('Use --dbexport [filename]'); process.exit(); } else { obj.db.GetAll(function (err, docs) { obj.fs.writeFileSync(obj.args.dbexport, JSON.stringify(docs)); console.log('Exported ' + docs.length + ' objects(s).'); process.exit(); }); }
236
+ if (obj.args.dbexport == true) { obj.args.dbexport = obj.path.join(obj.datapath, 'meshcentral.db.json'); }
237
+ obj.db.GetAll(function (err, docs) {
238
+ obj.fs.writeFileSync(obj.args.dbexport, JSON.stringify(docs));
239
+ console.log('Exported ' + docs.length + ' objects(s) to ' + obj.args.dbexport + '.'); process.exit();
240
+ });
241
return;
242
}
243
if (obj.args.dbimport) {
244
// Import the entire database from a JSON file
240
- if (obj.args.dbimport == true) { console.log('Use --dbimport [filename]'); process.exit(); } else {
241
- var json = null;
242
- try { json = obj.fs.readFileSync(obj.args.dbimport); } catch (e) { console.log('Invalid JSON file'); process.exit(); }
243
- try { json = JSON.parse(json); } catch (e) { console.log('Invalid JSON format'); process.exit(); }
244
- if ((json == null) || (typeof json.length != 'number') || (json.length < 1)) { console.log('Invalid JSON format'); }
245
- obj.db.RemoveAll(function () { obj.db.InsertMany(json, function () { console.log('Imported ' + json.length + ' objects(s)'); process.exit(); }); });
246
- }
245
+ if (obj.args.dbimport == true) { obj.args.dbimport = obj.path.join(obj.datapath, 'meshcentral.db.json'); }
246
+ var json = null;
247
+ try { json = obj.fs.readFileSync(obj.args.dbimport); } catch (e) { console.log('Invalid JSON file: ' + obj.args.dbimport + '.'); process.exit(); }
248
+ try { json = JSON.parse(json); } catch (e) { console.log('Invalid JSON format: ' + obj.args.dbimport + '.'); process.exit(); }
249
+ if ((json == null) || (typeof json.length != 'number') || (json.length < 1)) { console.log('Invalid JSON format: ' + obj.args.dbimport + '.'); }
250
+ obj.db.RemoveAll(function () { obj.db.InsertMany(json, function () { console.log('Imported ' + json.length + ' objects(s) from ' + obj.args.dbimport + '.'); process.exit(); }); });
251
return;
252
}
253
@@ -338,6 +342,12 @@ function CreateMeshCentralServer() {
342
obj.mpsserver = require('./mpsserver.js').CreateMpsServer(obj, obj.db, obj.args, obj.certificates);
343
}
344
345
+ // Setup and start the legacy swarm server
346
+ if (obj.certificates.swarmserver != null) {
347
+ if (obj.args.swarmport == null) { obj.args.swarmport = 8080; }
348
+ obj.swarmserver = require('./swarmserver.js').CreateSwarmServer(obj, obj.db, obj.args, obj.certificates);
349
+ }
350
+
351
// Start periodic maintenance
352
obj.maintenanceTimer = setInterval(obj.maintenanceActions, 1000 * 60 * 60); // Run this every hour
353
package.json
+1
-1
@@ -1,6 +1,6 @@
1
{
2
"name": "meshcentral",
3
- "version": "0.1.0-f",
3
+ "version": "0.1.0-g",
4
"keywords": [
5
"Remote Management",
6
"Intel AMT",
swarmserver.js
new
+207
@@ -0,0 +1,207 @@
1
+/**
2
+* @description Meshcentral1 legacy swarm server, used to update agents and get them on MeshCentral2
3
+* @author Ylian Saint-Hilaire
4
+* @version v0.0.1
5
+*/
6
+
7
+// Construct a legacy Swarm Server server object
8
+module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
9
+ var obj = {};
10
+ obj.parent = parent;
11
+ obj.db = db;
12
+ obj.args = args;
13
+ obj.certificates = certificates;
14
+ //obj.legacyAgentConnections = {};
15
+ var common = require('./common.js');
16
+ var net = require('net');
17
+ var tls = require('tls');
18
+
19
+ var LegacyMeshProtocol = {
20
+ NODEPUSH: 1, // Used to send a node block to another peer.
21
+ NODEPULL: 2, // Used to send a pull block to another peer.
22
+ NODENOTIFY: 3, // Used to indicate the node ID to other peers.
23
+ NODECHALLENGE: 4, // Used to challenge a node identity.
24
+ NODECRESPONSE: 5, // Used to respond to a node challenge.
25
+ TARGETSTATUS: 6, // Used to send the peer connection status list.
26
+ LOCALEVENT: 7, // Used to send local events to subscribers.
27
+ AESCRYPTO: 8, // Used to send an encrypted block of data.
28
+ SESSIONKEY: 9, // Used to send a session key to a remote node.
29
+ SYNCSTART: 10, // Used to send kick off the SYNC request, send the start NodeID.
30
+ SYNCMETADATA: 11, // Used to send a sequence of NodeID & serial numbers.
31
+ SYNCREQUEST: 12, // Used to send a sequence of NodeID's to request.
32
+ NODEID: 13, // Used to send the NodeID in the clear. Used for multicast.
33
+ AGENTID: 14, // Used to send the AgentID & version to the other node.
34
+ PING: 15, // Used to query a target for the presence of the mesh agent (PB_NODEID response expected).
35
+ SETUPADMIN: 16, // Used to set the trusted mesh identifier, this code can only be used from local settings file.
36
+ POLICY: 17, // Used to send a policy block to another peer.
37
+ POLICYSECRET: 18, // Used to encode the PKCS12 private key of a policy block.
38
+ EVENTMASK: 19, // Used by the mesh service to change the event mask.
39
+ RECONNECT: 20, // Used by the mesh service to indicate disconnect & reconnection after n seconds.
40
+ GETSTATE: 21, // Used by the mesh service to obtain agent state.
41
+ CERTENCRYPTED: 22, // Used to send a certificate encrypted message to a node.
42
+ GETCOOKIE: 23, // Used to request a certificate encryption anti-replay cookie.
43
+ COOKIE: 24, // Used to carry an anti-replay cookie to a requestor.
44
+ SESSIONCKEY: 25, // Used to send a session key to a remote console.
45
+ INTERFACE: 26, // Used to send a local interface blob to a management console.
46
+ MULTICAST: 27, // Used by the mesh service to cause the agent to send a multicast.
47
+ SELFEXE: 28, // Used to transfer our own agent executable.
48
+ LEADERBADGE: 29, // User to send a leadership badge.
49
+ NODEINFO: 30, // Used to indicate a block information update to the web service.
50
+ TARGETEVENT: 31, // Used to send a single target update event.
51
+ DEBUG: 33, // Used to send debug information to web service.
52
+ TCPRELAY: 34, // Used to operate mesh leader TCP relay sockets
53
+ CERTSIGNED: 35, // Used to send a certificate signed message to a node.
54
+ ERRORCODE: 36, // Used to notify of an error.
55
+ MESSAGE: 37, // Used to route messages between nodes.
56
+ CMESSAGE: 38, // Used to embed a interface identifier along with a PB_MESSAGE.
57
+ EMESSAGE: 39, // Used to embed a target encryption certificate along with a MESSAGE or CMESSAGE.
58
+ SEARCH: 40, // Used to send a custom search to one or more remote nodes.
59
+ MESSAGERELAY: 41, // Used by no-certificate consoles to send hopping messages to nodes.
60
+ USERINPUT: 42, // Used to send user keyboard input to a target computer
61
+ APPID: 43, // Used to send a block of data to a specific application identifier.
62
+ APPSUBSCRIBE: 44, // Used to perform local app subscription to an agent.
63
+ APPDIRECT: 45, // Used to send message directly to remote applications.
64
+ APPREQACK: 46, // Used to request an ack message.
65
+ APPACK: 47, // Used to ack a received message.
66
+ SERVERECHO: 48, // Server will echo this message, used for testing.
67
+ KVMINFO: 49, // Used to send local KVM slave process information to mesh agent.
68
+ REMOTEWAKE: 50, // Used to send remote wake information to server.
69
+ NEWCONNECTTOKEN: 51, // Used to send a new connection token to the Swarm Server.
70
+ WIFISCAN: 52, // Used to send visible WIFI AP's to the server.
71
+ AMTPROVISIONING: 53, // Used by the agent to send Intel AMT provisioning information to the server.
72
+ ANDROIDCOMMAND: 54, // Send a Android OS specific command (Android only).
73
+ NODEAPPDATA: 55, // Used to send application specific data block to the server for storage.
74
+ PROXY: 56, // Used to indicate the currently used proxy setting string.
75
+ FILEOPERATION: 57, // Used to perform short file operations.
76
+ APPSUBSCRIBERS: 58, // Used request and send to the mesh server the list of subscribed applications
77
+ CUSTOM: 100, // Message containing application specific data.
78
+ USERAUTH: 1000, // Authenticate a user to the swarm server.
79
+ USERMESH: 1001, // Request or return the mesh list for this console.
80
+ USERMESHS: 1002, // Send mesh overview information to the console.
81
+ USERNODES: 1003, // Send node overview information to the console.
82
+ JUSERMESHS: 1004, // Send mesh overview information to the console in JSON format.
83
+ JUSERNODES: 1005, // Send node overview information to the console in JSON format.
84
+ USERPOWERSTATE: 1006, // Used to send a power command from the console to the server.
85
+ JMESHPOWERTIMELINE: 1007, // Send the power timeline for all nodes in a mesh.
86
+ JMESHPOWERSUMMARY: 1008, // Send the power summary for sum of all nodes in a mesh.
87
+ USERCOMMAND: 1009, // Send a user admin text command to and from the server.
88
+ POWERBLOCK: 1010, // Request/Response of block of power state information.
89
+ MESHACCESSCHANGE: 1011, // Notify a console of a change in accessible meshes.
90
+ COOKIEAUTH: 1012, // Authenticate a user using a crypto cookie.
91
+ NODESTATECHANGE: 1013, // Indicates a node has changed power state.
92
+ JUSERNODE: 1014, // Send node overview information to the console in JSON format.
93
+ AMTWSMANEVENT: 1015, // Intel AMT WSMAN event sent to consoles.
94
+ ROUTINGCOOKIE: 1016, // Used by a console to request a routing cookie.
95
+ JCOLLABORATION: 1017, // Request/send back JSON collaboration state.
96
+ JRELATIONS: 1018, // Request/send back JSON relations state.
97
+ SETCOLLABSTATE: 1019, // Set the collaboration state for this session.
98
+ ADDRELATION: 1020, // Request that a new relation be added.
99
+ DELETERELATION: 1021, // Request a relation be deleted.
100
+ ACCEPTRELATION: 1022, // Request relation invitation be accepted.
101
+ RELATIONCHANGEEVENT: 1023, // Notify that a relation has changed.
102
+ COLLBCHANGEEVENT: 1024, // Notify that a collaboration state has change.
103
+ MULTICONSOLEMESSAGE: 1025, // Send a message to one or more console id's.
104
+ CONSOLEID: 1026, // Notify a console of it's console id.
105
+ CHANGERELATIONDATA: 1027, // Request that relation data be changed.
106
+ SETUSERDATA: 1028, // Set user data
107
+ GETUSERDATA: 1029, // Get user data
108
+ SERVERAUTH: 1030, // Used to verify the certificate of the server
109
+ USERAUTH2: 1031, // Authenticate a user to the swarm server (Uses SHA1 SALT)
110
+ GUESTREMOTEDESKTOP: 2001, // Guest usage: Remote Desktop
111
+ GUESTWEBRTCMESH: 2002 // Guest usage: WebRTC Mesh
112
+ }
113
+
114
+ obj.server = tls.createServer({ key: certificates.swarmserver.key, cert: certificates.swarmserver.cert, requestCert: true }, onConnection);
115
+ obj.server.listen(args.swarmport, function () { console.log('MeshCentral Legacy Swarm Server running on ' + certificates.CommonName + ':' + args.swarmport + '.'); }).on('error', function (err) { console.error('ERROR: MeshCentral Swarm Server server port ' + args.swarmport + ' is not available.'); if (args.exactports) { process.exit(); } });
116
+
117
+ function onConnection(socket) {
118
+ socket.tag = { first: true, clientCert: socket.getPeerCertificate(true), accumulator: "", socket: socket };
119
+ socket.setEncoding('binary');
120
+ Debug(1, 'SWARM:New legacy agent connection');
121
+
122
+ socket.addListener("data", function (data) {
123
+ if (args.swarmdebug) { var buf = new Buffer(data, "binary"); console.log('SWARM <-- (' + buf.length + '):' + buf.toString('hex')); } // Print out received bytes
124
+ socket.tag.accumulator += data;
125
+
126
+ // Detect if this is an HTTPS request, if it is, return a simple answer and disconnect. This is useful for debugging access to the MPS port.
127
+ if (socket.tag.first == true) {
128
+ if (socket.tag.accumulator.length < 3) return;
129
+ if (socket.tag.accumulator.substring(0, 3) == 'GET') { console.log("Swarm Connection, HTTP GET detected: " + socket.remoteAddress); socket.write('HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body>MeshCentral2 legacy swarm server.<br />MeshCentral1 mesh agents should connect here for updates.</body></html>'); socket.end(); return; }
130
+ socket.tag.first = false;
131
+ }
132
+
133
+ // A client certificate is required
134
+ if (!socket.tag.clientCert.subject) { console.log("Swarm Connection, no client cert: " + socket.remoteAddress); socket.write('HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nMeshCentral2 legacy swarm server.\r\nNo client certificate given.'); socket.end(); return; }
135
+
136
+ try {
137
+ // Parse all of the APF data we can
138
+ var l = 0;
139
+ do { l = ProcessCommand(socket); if (l > 0) { socket.tag.accumulator = socket.tag.accumulator.substring(l); } } while (l > 0);
140
+ if (l < 0) { socket.end(); }
141
+ } catch (e) {
142
+ console.log(e);
143
+ }
144
+ });
145
+
146
+ // Process one AFP command
147
+ function ProcessCommand(socket) {
148
+ if (socket.tag.accumulator.length < 4) return 0;
149
+ var cmd = common.ReadShort(socket.tag.accumulator, 0);
150
+ var len = common.ReadShort(socket.tag.accumulator, 2);
151
+ if (len > socket.tag.accumulator.length) return 0;
152
+
153
+ console.log('Swarm: Cmd=' + cmd + ', Len=' + len + '.');
154
+
155
+ switch (cmd) {
156
+ case LegacyMeshProtocol.NODEPUSH: {
157
+ Debug(3, 'Swarm:NODEPUSH');
158
+ }
159
+ default: {
160
+ Debug(1, 'Swarm:Unknown command: ' + cmd + ' of len ' + len + '.');
161
+ }
162
+ }
163
+ return len;
164
+ }
165
+
166
+ socket.addListener("close", function () {
167
+ Debug(1, 'Swarm:Connection closed');
168
+ try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
169
+ obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
170
+ });
171
+
172
+ socket.addListener("error", function () {
173
+ //console.log("Swarm Error: " + socket.remoteAddress);
174
+ });
175
+ }
176
+
177
+ // Disconnect legacy agent connection
178
+ obj.close = function (socket) {
179
+ try { socket.close(); } catch (e) { }
180
+ try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
181
+ obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
182
+ }
183
+
184
+ function Write(socket, data) {
185
+ if (args.swarmdebug) {
186
+ // Print out sent bytes
187
+ var buf = new Buffer(data, "binary");
188
+ console.log('Swarm --> (' + buf.length + '):' + buf.toString('hex'));
189
+ socket.write(buf);
190
+ } else {
191
+ socket.write(new Buffer(data, "binary"));
192
+ }
193
+ }
194
+
195
+ // Debug
196
+ function Debug(lvl) {
197
+ if (lvl > obj.parent.debugLevel) return;
198
+ if (arguments.length == 2) { console.log(arguments[1]); }
199
+ else if (arguments.length == 3) { console.log(arguments[1], arguments[2]); }
200
+ else if (arguments.length == 4) { console.log(arguments[1], arguments[2], arguments[3]); }
201
+ else if (arguments.length == 5) { console.log(arguments[1], arguments[2], arguments[3], arguments[4]); }
202
+ else if (arguments.length == 6) { console.log(arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]); }
203
+ else if (arguments.length == 7) { console.log(arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6]); }
204
+ }
205
+
206
+ return obj;
207
+}