Added multi-interface mesh server scanner

Ylian Saint-Hilaire committed Sep 1, 2017 at 13:45 UTC 362b23c088289034f5317a5eaf50c8d0d266b75f
2 files changed +109 -40
meshscanner.js
+108 -39
@@ -11,8 +11,8 @@ module.exports.CreateMeshScanner = function (parent) {
11 obj.parent = parent;
12 obj.dgram = require('dgram');
13 obj.common = require('./common.js');
14 - obj.server4 = null;
15 - obj.server6 = null;
14 + obj.servers4 = {};
15 + obj.servers6 = {};
16 obj.mainTimer = null;
17 var periodicScanTime = (60000 * 20); // Interval between scans, 20 minutes.
18 var membershipIPv4 = '239.255.255.235';
@@ -20,6 +20,91 @@ module.exports.CreateMeshScanner = function (parent) {
20 obj.agentCertificatHashHex = parent.certificateOperations.forge.pki.getPublicKeyFingerprint(parent.certificateOperations.forge.pki.certificateFromPem(parent.certificates.agent.cert).publicKey, { md: parent.certificateOperations.forge.md.sha256.create(), encoding: 'hex' });
21 obj.error = 0;
22
23 + // Get a list of IPv4 and IPv6 interface addresses
24 + function getInterfaceList() {
25 + var ipv4 = [];
26 + var ipv6 = [];
27 + var interfaces = require('os').networkInterfaces();
28 + for (var i in interfaces) {
29 + var interface = interfaces[i];
30 + for (var j in interface) {
31 + var interface2 = interface[j];
32 + if ((interface2.mac != '00:00:00:00:00:00') && (interface2.internal == false)) {
33 + if (interface2.family == 'IPv4') { ipv4.push(interface2.address); }
34 + if (interface2.family == 'IPv6') { ipv6.push(interface2.address); }
35 + }
36 + }
37 + }
38 + return { ipv4: ipv4, ipv6: ipv6 };
39 + }
40 +
41 + // Setup all IPv4 and IPv6 servers
42 + function setupServers() {
43 + var addresses = getInterfaceList();
44 + for (var i in obj.servers4) { obj.servers4[i].xxclear = true; }
45 + for (var i in obj.servers6) { obj.servers6[i].xxclear = true; }
46 + for (var i in addresses.ipv4) {
47 + var localAddress = addresses.ipv4[i];
48 + if (obj.servers4[localAddress] != null) {
49 + // Server already exists
50 + obj.servers4[localAddress].xxclear = false;
51 + } else {
52 + // Create a new IPv4 server
53 + var server4 = obj.dgram.createSocket("udp4");
54 + server4.xxclear = false;
55 + server4.xxtype = 4;
56 + server4.xxlocal = localAddress;
57 + server4.on('error', function (err) { console.log("ERROR: Server port " + server4.xxlocal + ":16989 not available, check if server is running twice."); server4.close(); server4 = null; });
58 + server4.bind({ address: server4.xxlocal, port: 16989, exclusive: false }, function () {
59 + try {
60 + server4.setBroadcast(true);
61 + server4.setMulticastTTL(128);
62 + server4.addMembership(membershipIPv4);
63 + server4.on('error', function (error) { console.log('Error: ' + error); });
64 + server4.on('message', function (msg, info) { onUdpPacket(msg, info, server4); });
65 + obj.performScan(server4);
66 + obj.performScan(server4);
67 + } catch (e) { }
68 + });
69 + obj.servers4[localAddress] = server4;
70 + }
71 + }
72 + for (var i in addresses.ipv6) {
73 + var localAddress = addresses.ipv6[i];
74 + if (obj.servers6[localAddress] != null) {
75 + // Server already exists
76 + obj.servers6[localAddress].xxclear = false;
77 + } else {
78 + // Create a new IPv6 server
79 + var server6 = obj.dgram.createSocket("udp6", localAddress);
80 + server6.xxclear = false;
81 + server6.xxtype = 6;
82 + server6.xxlocal = localAddress;
83 + server6.on('error', function (err) { console.log("ERROR: Server port " + server6.xxlocal + ":16989 not available, check if server is running twice.");server6.close(); obj.server6 = null; });
84 + server6.bind({ address: server6.xxlocal, port: 16989, exclusive: false }, function () {
85 + try {
86 + server6.setBroadcast(true);
87 + server6.setMulticastTTL(128);
88 + server6.addMembership(membershipIPv6);
89 + server6.on('error', function (error) { console.log('Error: ' + error); });
90 + server6.on('message', function (msg, info) { onUdpPacket(msg, info, server6); });
91 + performScan(server6);
92 + performScan(server6);
93 + } catch (e) { }
94 + });
95 + obj.servers6[localAddress] = server6;
96 + }
97 + }
98 + for (var i in obj.servers4) { if (obj.servers4[i].xxclear == true) { obj.servers4[i].close(); delete obj.servers4[i]; }; }
99 + for (var i in obj.servers6) { if (obj.servers6[i].xxclear == true) { obj.servers6[i].close(); delete obj.servers6[i]; }; }
100 + }
101 +
102 + // Clear all IPv4 and IPv6 servers
103 + function clearServers() {
104 + for (var i in obj.servers4) { obj.servers4[i].close(); delete obj.servers4[i]; }
105 + for (var i in obj.servers6) { obj.servers6[i].close(); delete obj.servers6[i]; }
106 + }
107 +
108 // Start scanning for local network Mesh Agents
109 obj.start = function () {
110 if (obj.server4 != null) return;
@@ -27,28 +112,7 @@ module.exports.CreateMeshScanner = function (parent) {
112 obj.multicastPacket4 = Buffer.from("MeshCentral2|" + obj.agentCertificatHashHex.toUpperCase() + '|' + url, 'ascii');
113 url = (parent.args.notls ? 'ws' : 'wss') + '://[%s]:' + parent.args.port + '/agent.ashx';
114 obj.multicastPacket6 = Buffer.from("MeshCentral2|" + obj.agentCertificatHashHex.toUpperCase() + '|' + url, 'ascii');
30 - obj.server4 = obj.dgram.createSocket("udp4");
31 - obj.server4.on('error', function(err) { if (obj.error++ == 0) { console.log("ERROR: Server port 16989 not available, check if server is running twice."); } obj.server4.close(); obj.server4 = null; });
32 - obj.server4.bind(16989, function () {
33 - obj.server4.setBroadcast(true)
34 - obj.server4.setMulticastTTL(128);
35 - obj.server4.addMembership(membershipIPv4);
36 - obj.server4.on('error', function (error) { console.log('Error: ' + error); });
37 - obj.server4.on('message', onUdpPacket); // TODO!!! We can't use this server for receive, instead we have to bind a seperate UDP server for each of the network interfaces.
38 - obj.performScan(4);
39 - obj.performScan(4);
40 - });
41 - obj.server6 = obj.dgram.createSocket("udp6");
42 - obj.server6.on('error', function(err) { obj.server6.close(); obj.server6 = null; }); // IPv6 may not be supported.
43 - obj.server6.bind(16989, function () {
44 - obj.server6.setBroadcast(true)
45 - obj.server6.setMulticastTTL(128);
46 - obj.server6.addMembership(membershipIPv6);
47 - obj.server6.on('error', function (error) { console.log('Error: ' + error); });
48 - obj.server6.on('message', onUdpPacket); // TODO!!! We can't use this server for receive, instead we have to bind a seperate UDP server for each of the network interfaces.
49 - obj.performScan(6);
50 - obj.performScan(6);
51 - });
115 + setupServers();
116 obj.mainTimer = setInterval(obj.performScan, periodicScanTime);
117 return obj;
118 }
@@ -56,22 +120,27 @@ module.exports.CreateMeshScanner = function (parent) {
120 // Stop scanning for local network Mesh Agents
121 obj.stop = function () {
122 if (obj.mainTimer != null) { clearInterval(obj.mainTimer); obj.mainTimer = null; }
59 - if (obj.server4 != null) { obj.server4.close(); obj.server4 = null; }
60 - if (obj.server6 != null) { obj.server6.close(); obj.server6 = null; }
123 + clearServers();
124 }
125
126 // Look for all Mesh Agents that may be locally reachable, indicating the presense of this server.
64 - obj.performScan = function (mode) {
65 - if ((mode != 6) && (obj.server4 != null)) { obj.server4.send(obj.multicastPacket4, 0, obj.multicastPacket4.length, 16990, membershipIPv4); }
66 - if ((mode != 4) && (obj.server6 != null)) { obj.server6.send(obj.multicastPacket6, 0, obj.multicastPacket6.length, 16990, membershipIPv6); }
127 + obj.performScan = function (server) {
128 + if (server != null) {
129 + if (server.xxtype == 4) { server.send(obj.multicastPacket4, 0, obj.multicastPacket4.length, 16990, membershipIPv4); }
130 + if (server.xxtype == 6) { server.send(obj.multicastPacket6, 0, obj.multicastPacket6.length, 16990, membershipIPv6); }
131 + } else {
132 + for (var i in obj.servers4) { obj.servers4[i].send(obj.multicastPacket4, 0, obj.multicastPacket4.length, 16990, membershipIPv4); }
133 + for (var i in obj.servers6) { obj.servers6[i].send(obj.multicastPacket6, 0, obj.multicastPacket6.length, 16990, membershipIPv6); }
134 + setupServers(); // Check if any network interfaces where added or removed
135 + }
136 }
137
138 // Called when a UDP packet is received from an agent.
70 - function onUdpPacket(msg, info) {
71 - //console.log('Received ' + msg.length + ' bytes from ' + info.address + ':' + info.port + '\n');
139 + function onUdpPacket(msg, info, server) {
140 + // console.log('Received ' + msg.length + ' bytes from ' + info.address + ':' + info.port + ', on interface: ' + server.xxlocal + '.');
141 if ((msg.length == 64) && (msg.toString('ascii') == obj.agentCertificatHashHex.toUpperCase())) {
73 - if (info.family == 'IPv4') { obj.server4.send(obj.multicastPacket4, 0, obj.multicastPacket4.length, info.port, info.address); }
74 - if (info.family == 'IPv6') { obj.server6.send(obj.multicastPacket6, 0, obj.multicastPacket6.length, info.port, info.address); }
142 + if (server.xxtype == 4) { server.send(obj.multicastPacket4, 0, obj.multicastPacket4.length, info.port, info.address); }
143 + if (server.xxtype == 6) { server.send(obj.multicastPacket6, 0, obj.multicastPacket6.length, info.port, info.address); }
144 }
145 }
146
@@ -85,15 +154,15 @@ module.exports.CreateMeshScanner = function (parent) {
154 //console.log(wakepacket.toString('hex'));
155
156 // Send the wake packet 3 times with small time intervals
88 - if (obj.server4) { obj.server4.send(wakepacket, 0, wakepacket.length, 7, "255.255.255.255"); obj.server4.send(wakepacket, 0, wakepacket.length, 16990, membershipIPv4); }
89 - if (obj.server6) { obj.server6.send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
157 + for (var i in obj.servers4) { obj.servers4[i].send(wakepacket, 0, wakepacket.length, 7, "255.255.255.255"); obj.servers4[i].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv4); }
158 + for (var i in obj.servers6) { obj.servers6[i].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
159 setTimeout(function () {
91 - if (obj.server4) { obj.server4.send(wakepacket, 0, wakepacket.length, 7, "255.255.255.255"); obj.server4.send(wakepacket, 0, wakepacket.length, 16990, membershipIPv4); }
92 - if (obj.server6) { obj.server6.send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
160 + for (var i in obj.servers4) { obj.servers4[i].send(wakepacket, 0, wakepacket.length, 7, "255.255.255.255"); obj.servers4[i].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv4); }
161 + for (var i in obj.servers6) { obj.servers6[i].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
162 }, 200);
163 setTimeout(function () {
95 - if (obj.server4) { obj.server4.send(wakepacket, 0, wakepacket.length, 7, "255.255.255.255"); obj.server4.send(wakepacket, 0, wakepacket.length, 16990, membershipIPv4); }
96 - if (obj.server6) { obj.server6.send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
164 + for (var i in obj.servers4) { obj.servers4[i].send(wakepacket, 0, wakepacket.length, 7, "255.255.255.255"); obj.servers4[i].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv4); }
165 + for (var i in obj.servers6) { obj.servers6[i].send(wakepacket, 0, wakepacket.length, 16990, membershipIPv6); }
166 }, 500);
167 }
168 }
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.0.6-x",
3 + "version": "0.0.6-y",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",