Added public IP location information to the mesh agent
Ylian Saint-Hilaire committed
Aug 28, 2017 at 12:48 UTC
888e8dedefc26919dc0df237c090b24f10712f47
4 files changed
+122
-32
agents/MeshService.exe
Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ
agents/MeshService64.exe
Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ
agents/meshcore.js
+116
-32
@@ -24,6 +24,7 @@ function createMeshCore(agent) {
24
var tunnels = {};
25
var lastSelfInfo = null;
26
var lastNetworkInfo = null;
27
+ var lastPublicLocationInfo = null;
28
var selfInfoUpdateTimer = null;
29
30
var http = require('http');
@@ -44,6 +45,67 @@ function createMeshCore(agent) {
45
var mesh = agent.getMeshApi();
46
}
47
48
+ // Get our location (lat/long) using our public IP address
49
+ function getIpLocationDataEx(func) {
50
+ try {
51
+ http.request({
52
+ host: 'ipinfo.io', // TODO: Use a HTTP proxy if needed!!!!
53
+ port: 80,
54
+ path: 'http://ipinfo.io/json', // Use this service to get our geolocation
55
+ headers: { Host: "ipinfo.io" }
56
+ },
57
+ function (resp) {
58
+ var geoData = '';
59
+ resp.data = function (geoipdata) { geoData += geoipdata; };
60
+ resp.end = function () {
61
+ var location = null;
62
+ try { if (typeof geoData == 'string') { var result = JSON.parse(geoData); if (result.ip && result.loc) { location = result; } } } catch (e) { }
63
+ if (func) { func(location); }
64
+ }
65
+ }).end();
66
+ }
67
+ catch (e) { }
68
+ }
69
+
70
+ // Remove all Gateway MAC addresses for interface list. This is useful because the gateway MAC is not always populated reliably.
71
+ function clearGatewayMac(str) {
72
+ if (str == null) return null;
73
+ var x = JSON.parse(str);
74
+ for (var i in x.netif) { if (x.netif[i].gatewaymac) { delete x.netif[i].gatewaymac } }
75
+ return JSON.stringify(x);
76
+ }
77
+
78
+ function getIpLocationData(func) {
79
+ // Get the location information for the cache if possible
80
+ var publicLocationInfo = db.Get('publicLocationInfo');
81
+ if (publicLocationInfo != null) { publicLocationInfo = JSON.parse(publicLocationInfo); }
82
+ if (publicLocationInfo == null) {
83
+ // Nothing in the cache, fetch the data
84
+ getIpLocationDataEx(function (locationData) {
85
+ publicLocationInfo = {};
86
+ publicLocationInfo.netInfoStr = lastNetworkInfo;
87
+ publicLocationInfo.locationData = locationData;
88
+ var x = db.Put('publicLocationInfo', JSON.stringify(publicLocationInfo)); // Save to database
89
+ if (func) func(locationData);
90
+ });
91
+ } else {
92
+ // Check the cache
93
+ if (clearGatewayMac(publicLocationInfo.netInfoStr) == clearGatewayMac(lastNetworkInfo)) {
94
+ // Cache match
95
+ if (func) func(publicLocationInfo.locationData);
96
+ } else {
97
+ // Cache mismatch
98
+ getIpLocationDataEx(function (locationData) {
99
+ publicLocationInfo = {};
100
+ publicLocationInfo.netInfoStr = lastNetworkInfo;
101
+ publicLocationInfo.locationData = locationData;
102
+ var x = db.Put('publicLocationInfo', JSON.stringify(publicLocationInfo)); // Save to database
103
+ if (func) func(locationData);
104
+ });
105
+ }
106
+ }
107
+ }
108
+
109
// Polyfill String.endsWith
110
if (!String.prototype.endsWith) {
111
String.prototype.endsWith = function (searchString, position) {
@@ -149,38 +211,47 @@ function createMeshCore(agent) {
211
function handleServerCommand(data) {
212
if (typeof data == 'object') {
213
// If this is a console command, parse it and call the console handler
152
- if (data.action == 'msg') {
153
- if (data.type == 'console') { // Process a console command
154
- if (data.value && data.sessionid) {
155
- var args = splitArgs(data.value);
156
- processConsoleCommand(args[0].toLowerCase(), parseArgs(args), data.rights, data.sessionid);
214
+ switch (data.action) {
215
+ case 'msg': {
216
+ if (data.type == 'console') { // Process a console command
217
+ if (data.value && data.sessionid) {
218
+ var args = splitArgs(data.value);
219
+ processConsoleCommand(args[0].toLowerCase(), parseArgs(args), data.rights, data.sessionid);
220
+ }
221
}
158
- }
159
- else if (data.type == 'tunnel') { // Process a new tunnel connection request
160
- if (data.value && data.sessionid) {
161
- // Create a new tunnel object
162
- var tunnel = http.request(parseUrl(data.value));
163
- tunnel.upgrade = onTunnelUpgrade;
164
- tunnel.sessionid = data.sessionid;
165
- tunnel.rights = data.rights;
166
- tunnel.state = 0;
167
- tunnel.url = data.value;
168
- tunnel.protocol = 0;
169
-
170
- // Put the tunnel in the tunnels list
171
- var index = 1;
172
- while (tunnels[index]) { index++; }
173
- tunnel.index = index;
174
- tunnels[index] = tunnel;
175
-
176
- sendConsoleText('New tunnel connection #' + index + ': ' + tunnel.url + ', rights: ' + tunnel.rights, data.sessionid);
222
+ else if (data.type == 'tunnel') { // Process a new tunnel connection request
223
+ if (data.value && data.sessionid) {
224
+ // Create a new tunnel object
225
+ var tunnel = http.request(parseUrl(data.value));
226
+ tunnel.upgrade = onTunnelUpgrade;
227
+ tunnel.sessionid = data.sessionid;
228
+ tunnel.rights = data.rights;
229
+ tunnel.state = 0;
230
+ tunnel.url = data.value;
231
+ tunnel.protocol = 0;
232
+
233
+ // Put the tunnel in the tunnels list
234
+ var index = 1;
235
+ while (tunnels[index]) { index++; }
236
+ tunnel.index = index;
237
+ tunnels[index] = tunnel;
238
+
239
+ sendConsoleText('New tunnel connection #' + index + ': ' + tunnel.url + ', rights: ' + tunnel.rights, data.sessionid);
240
+ }
241
}
242
+ break;
243
+ }
244
+ case 'wakeonlan': {
245
+ // Send wake-on-lan on all interfaces for all MAC addresses in data.macs array. The array is a list of HEX MAC addresses.
246
+ sendConsoleText('Server requesting wake-on-lan for: ' + data.macs.join(', '));
247
+ // TODO!!!!
248
+ break;
249
+ }
250
+ case 'location': {
251
+ // Update the location information of this node
252
+ getIpLocationData(function (location) { mesh.SendCommand({ "action": "location", "type": "publicip", "value": location }); });
253
+ break;
254
}
179
- }
180
- else if (data.action == 'wakeonlan') {
181
- // Send wake-on-lan on all interfaces for all MAC addresses in data.macs array. The array is a list of HEX MAC addresses.
182
- sendConsoleText('Server requesting wake-on-lan for: ' + data.macs.join(', '));
183
- // TODO!!!!
255
}
256
}
257
}
@@ -449,7 +520,7 @@ function createMeshCore(agent) {
520
var response = null;
521
switch (cmd) {
522
case 'help': { // Displays available commands
452
- response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseurl, httpget, wsconnect, wssend, wsclose, notify, ls, amt, netinfo.';
523
+ response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseurl, httpget, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location.';
524
break;
525
}
526
case 'notify': { // Send a notification message to the mesh
@@ -656,6 +727,10 @@ function createMeshCore(agent) {
727
sendConsoleText(args['_'].join(' '));
728
break;
729
}
730
+ case 'location': {
731
+ getIpLocationData(function (location) { sendConsoleText("Public IP location:\r\n" + objToString(location, 0, '.'), sessionid); }, args['_'][0]);
732
+ break;
733
+ }
734
default: { // This is an unknown command, return an error message
735
response = 'Unknown command \"' + cmd + '\", type \"help\" for list of avaialble commands.';
736
break;
@@ -666,7 +741,10 @@ function createMeshCore(agent) {
741
}
742
743
// Send a mesh agent console command
669
- function sendConsoleText(text, sessionid) { mesh.SendCommand({ "action": "msg", "type": "console", "value": text, "sessionid": sessionid }); }
744
+ function sendConsoleText(text, sessionid) {
745
+ if (typeof text == 'object') { text = JSON.stringify(text); }
746
+ mesh.SendCommand({ "action": "msg", "type": "console", "value": text, "sessionid": sessionid });
747
+ }
748
749
// Called before the process exits
750
//process.exit = function (code) { console.log("Exit with code: " + code.toString()); }
@@ -712,7 +790,13 @@ function createMeshCore(agent) {
790
var netInfo = mesh.NetInfo;
791
netInfo.action = 'netinfo';
792
var netInfoStr = JSON.stringify(netInfo);
715
- if ((force == true) || (netInfoStr != lastNetworkInfo)) { mesh.SendCommand(netInfo); lastNetworkInfo = netInfoStr; }
793
+ if ((force == true) || (clearGatewayMac(netInfoStr) != clearGatewayMac(lastNetworkInfo))) { mesh.SendCommand(netInfo); lastNetworkInfo = netInfoStr; }
794
+
795
+ // Update public IP location information, location caching will be used
796
+ getIpLocationData(function (location) {
797
+ var locationStr = JSON.stringify(location);
798
+ if ((force == true) || (locationStr != lastPublicLocationInfo)) { mesh.SendCommand({ "action": "location", "type": "publicip", "value": location }); lastPublicLocationInfo = locationStr; }
799
+ });
800
}
801
802
// Called on MicroLMS Intel AMT user notification
meshagent.js
+6
@@ -388,6 +388,12 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
388
// Event the node interface information change
389
obj.parent.parent.DispatchEvent(['*', obj.meshid], obj, { action: 'ifchange', nodeid: obj.dbNodeKey, domain: domain.id, nolog: 1 });
390
391
+ break;
392
+ }
393
+ case 'location':
394
+ {
395
+ // Sent by the agent to update location information
396
+ console.log(JSON.stringify(command));
397
break;
398
}
399
}