1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 | const os = require('os');
|
17 | const exec = require('child_process').exec;
|
18 | const execSync = require('child_process').execSync;
|
19 | const fs = require('fs');
|
20 | const util = require('./util');
|
21 |
|
22 | let _platform = process.platform;
|
23 |
|
24 | const _linux = (_platform === 'linux');
|
25 | const _darwin = (_platform === 'darwin');
|
26 | const _windows = (_platform === 'win32');
|
27 | const _freebsd = (_platform === 'freebsd');
|
28 | const _openbsd = (_platform === 'openbsd');
|
29 | const _netbsd = (_platform === 'netbsd');
|
30 | const _sunos = (_platform === 'sunos');
|
31 |
|
32 | let _network = {};
|
33 | let _default_iface = '';
|
34 | let _ifaces = {};
|
35 | let _dhcpNics = [];
|
36 | let _networkInterfaces = [];
|
37 | let _mac = {};
|
38 | let pathToIp;
|
39 |
|
40 | function getDefaultNetworkInterface() {
|
41 |
|
42 | let ifaces = os.networkInterfaces();
|
43 | let ifacename = '';
|
44 | let ifacenameFirst = '';
|
45 |
|
46 | let scopeid = 9999;
|
47 |
|
48 |
|
49 | for (let dev in ifaces) {
|
50 | if ({}.hasOwnProperty.call(ifaces, dev)) {
|
51 | ifaces[dev].forEach(function (details) {
|
52 | if (details && details.internal === false) {
|
53 | ifacenameFirst = ifacenameFirst || dev;
|
54 | if (details.scopeid && details.scopeid < scopeid) {
|
55 | ifacename = dev;
|
56 | scopeid = details.scopeid;
|
57 | }
|
58 | }
|
59 | });
|
60 | }
|
61 | }
|
62 | ifacename = ifacename || ifacenameFirst || '';
|
63 |
|
64 | try {
|
65 | if (_windows) {
|
66 |
|
67 | let defaultIp = '';
|
68 | const cmd = 'netstat -r';
|
69 | const result = execSync(cmd);
|
70 | const lines = result.toString().split(os.EOL);
|
71 | lines.forEach(line => {
|
72 | line = line.replace(/\s+/g, ' ').trim();
|
73 | if (line.indexOf('0.0.0.0 0.0.0.0') > -1 && !(/[a-zA-Z]/.test(line))) {
|
74 | const parts = line.split(' ');
|
75 | if (parts.length >= 5) {
|
76 | defaultIp = parts[parts.length - 2];
|
77 | }
|
78 | }
|
79 | });
|
80 | if (defaultIp) {
|
81 | for (let dev in ifaces) {
|
82 | if ({}.hasOwnProperty.call(ifaces, dev)) {
|
83 | ifaces[dev].forEach(function (details) {
|
84 | if (details && details.address && details.address === defaultIp) {
|
85 | ifacename = dev;
|
86 | }
|
87 | });
|
88 | }
|
89 | }
|
90 | }
|
91 | }
|
92 | if (_linux) {
|
93 | let cmd = 'ip route 2> /dev/null | grep default';
|
94 | let result = execSync(cmd);
|
95 | let parts = result.toString().split('\n')[0].split(/\s+/);
|
96 | if (parts[0] === 'none' && parts[5]) {
|
97 | ifacename = parts[5];
|
98 | } else if (parts[4]) {
|
99 | ifacename = parts[4];
|
100 | }
|
101 |
|
102 | if (ifacename.indexOf(':') > -1) {
|
103 | ifacename = ifacename.split(':')[1].trim();
|
104 | }
|
105 | }
|
106 | if (_darwin || _freebsd || _openbsd || _netbsd || _sunos) {
|
107 | let cmd = '';
|
108 | if (_linux) cmd = 'ip route 2> /dev/null | grep default | awk \'{print $5}\'';
|
109 | if (_darwin) cmd = 'route -n get default 2>/dev/null | grep interface: | awk \'{print $2}\'';
|
110 | if (_freebsd || _openbsd || _netbsd || _sunos) cmd = 'route get 0.0.0.0 | grep interface:';
|
111 | let result = execSync(cmd);
|
112 | ifacename = result.toString().split('\n')[0];
|
113 | if (ifacename.indexOf(':') > -1) {
|
114 | ifacename = ifacename.split(':')[1].trim();
|
115 | }
|
116 | }
|
117 | } catch (e) {
|
118 | util.noop();
|
119 | }
|
120 | if (ifacename) _default_iface = ifacename;
|
121 | return _default_iface;
|
122 | }
|
123 |
|
124 | exports.getDefaultNetworkInterface = getDefaultNetworkInterface;
|
125 |
|
126 | function getMacAddresses() {
|
127 | let iface = '';
|
128 | let mac = '';
|
129 | let result = {};
|
130 | if (_linux || _freebsd || _openbsd || _netbsd) {
|
131 | if (typeof pathToIp === 'undefined') {
|
132 | try {
|
133 | const lines = execSync('which ip').toString().split('\n');
|
134 | if (lines.length && lines[0].indexOf(':') === -1 && lines[0].indexOf('/') === 0) {
|
135 | pathToIp = lines[0];
|
136 | } else {
|
137 | pathToIp = '';
|
138 | }
|
139 | } catch (e) {
|
140 | pathToIp = '';
|
141 | }
|
142 | }
|
143 | try {
|
144 | const cmd = 'export LC_ALL=C; ' + ((pathToIp) ? pathToIp + ' link show up' : '/sbin/ifconfig') + '; unset LC_ALL';
|
145 | let res = execSync(cmd);
|
146 | const lines = res.toString().split('\n');
|
147 | for (let i = 0; i < lines.length; i++) {
|
148 | if (lines[i] && lines[i][0] !== ' ') {
|
149 | if (pathToIp) {
|
150 | let nextline = lines[i + 1].trim().split(' ');
|
151 | if (nextline[0] === 'link/ether') {
|
152 | iface = lines[i].split(' ')[1];
|
153 | iface = iface.slice(0, iface.length - 1);
|
154 | mac = nextline[1];
|
155 | }
|
156 | } else {
|
157 | iface = lines[i].split(' ')[0];
|
158 | mac = lines[i].split('HWaddr ')[1];
|
159 | }
|
160 |
|
161 | if (iface && mac) {
|
162 | result[iface] = mac.trim();
|
163 | iface = '';
|
164 | mac = '';
|
165 | }
|
166 | }
|
167 | }
|
168 | } catch (e) {
|
169 | util.noop();
|
170 | }
|
171 | }
|
172 | if (_darwin) {
|
173 | try {
|
174 | const cmd = '/sbin/ifconfig';
|
175 | let res = execSync(cmd);
|
176 | const lines = res.toString().split('\n');
|
177 | for (let i = 0; i < lines.length; i++) {
|
178 | if (lines[i] && lines[i][0] !== '\t' && lines[i].indexOf(':') > 0) {
|
179 | iface = lines[i].split(':')[0];
|
180 | } else if (lines[i].indexOf('\tether ') === 0) {
|
181 | mac = lines[i].split('\tether ')[1];
|
182 | if (iface && mac) {
|
183 | result[iface] = mac.trim();
|
184 | iface = '';
|
185 | mac = '';
|
186 | }
|
187 | }
|
188 | }
|
189 | } catch (e) {
|
190 | util.noop();
|
191 | }
|
192 | }
|
193 | return result;
|
194 | }
|
195 |
|
196 | function networkInterfaceDefault(callback) {
|
197 |
|
198 | return new Promise((resolve) => {
|
199 | process.nextTick(() => {
|
200 | let result = getDefaultNetworkInterface();
|
201 | if (callback) { callback(result); }
|
202 | resolve(result);
|
203 | });
|
204 | });
|
205 | }
|
206 |
|
207 | exports.networkInterfaceDefault = networkInterfaceDefault;
|
208 |
|
209 |
|
210 |
|
211 |
|
212 | function parseLinesWindowsNics(sections, nconfigsections) {
|
213 | let nics = [];
|
214 | for (let i in sections) {
|
215 | if ({}.hasOwnProperty.call(sections, i)) {
|
216 |
|
217 | if (sections[i].trim() !== '') {
|
218 |
|
219 | let lines = sections[i].trim().split('\r\n');
|
220 | let linesNicConfig = nconfigsections[i].trim().split('\r\n');
|
221 | let netEnabled = util.getValue(lines, 'NetEnabled', '=');
|
222 |
|
223 | if (netEnabled !== '') {
|
224 | const speed = parseInt(util.getValue(lines, 'speed', '=').trim(), 10) / 1000000;
|
225 | nics.push({
|
226 | mac: util.getValue(lines, 'MACAddress', '=').toLowerCase(),
|
227 | dhcp: util.getValue(linesNicConfig, 'dhcpEnabled', '=').toLowerCase(),
|
228 | name: util.getValue(lines, 'Name', '=').replace(/\]/g, ')').replace(/\[/g, '('),
|
229 | netEnabled: netEnabled === 'TRUE',
|
230 | speed: isNaN(speed) ? -1 : speed,
|
231 | operstate: util.getValue(lines, 'NetConnectionStatus', '=') === '2' ? 'up' : 'down',
|
232 | type: util.getValue(lines, 'AdapterTypeID', '=') === '9' ? 'wireless' : 'wired'
|
233 | });
|
234 | }
|
235 | }
|
236 | }
|
237 | }
|
238 | return nics;
|
239 | }
|
240 |
|
241 | function getWindowsNics() {
|
242 | const cmd = util.getWmic() + ' nic get MACAddress, name, NetEnabled, Speed, NetConnectionStatus, AdapterTypeId /value';
|
243 | const cmdnicconfig = util.getWmic() + ' nicconfig get dhcpEnabled /value';
|
244 | try {
|
245 | const nsections = execSync(cmd, util.execOptsWin).split(/\n\s*\n/);
|
246 | const nconfigsections = execSync(cmdnicconfig, util.execOptsWin).split(/\n\s*\n/);
|
247 | return (parseLinesWindowsNics(nsections, nconfigsections));
|
248 | } catch (e) {
|
249 | return [];
|
250 | }
|
251 | }
|
252 |
|
253 | function getWindowsDNSsuffixes() {
|
254 |
|
255 | let iface = {};
|
256 |
|
257 | let dnsSuffixes = {
|
258 | primaryDNS: '',
|
259 | exitCode: 0,
|
260 | ifaces: [],
|
261 | };
|
262 |
|
263 | try {
|
264 | const ipconfig = execSync('ipconfig /all', util.execOptsWin);
|
265 | const ipconfigArray = ipconfig.split('\r\n\r\n');
|
266 |
|
267 | ipconfigArray.forEach((element, index) => {
|
268 |
|
269 | if (index == 1) {
|
270 | const longPrimaryDNS = element.split('\r\n').filter((element) => {
|
271 | return element.toUpperCase().includes('DNS');
|
272 | });
|
273 | const primaryDNS = longPrimaryDNS[0].substring(longPrimaryDNS[0].lastIndexOf(':') + 1);
|
274 | dnsSuffixes.primaryDNS = primaryDNS.trim();
|
275 | if (!dnsSuffixes.primaryDNS) dnsSuffixes.primaryDNS = 'Not defined';
|
276 | }
|
277 | if (index > 1) {
|
278 | if (index % 2 == 0) {
|
279 | const name = element.substring(element.lastIndexOf(' ') + 1).replace(':', '');
|
280 | iface.name = name;
|
281 | } else {
|
282 | const connectionSpecificDNS = element.split('\r\n').filter((element) => {
|
283 | return element.toUpperCase().includes('DNS');
|
284 | });
|
285 | const dnsSuffix = connectionSpecificDNS[0].substring(connectionSpecificDNS[0].lastIndexOf(':') + 1);
|
286 | iface.dnsSuffix = dnsSuffix.trim();
|
287 | dnsSuffixes.ifaces.push(iface);
|
288 | iface = {};
|
289 | }
|
290 | }
|
291 | });
|
292 |
|
293 | return dnsSuffixes;
|
294 | } catch (error) {
|
295 |
|
296 | return {
|
297 | primaryDNS: '',
|
298 | exitCode: 0,
|
299 | ifaces: [],
|
300 | };
|
301 | }
|
302 | }
|
303 |
|
304 | function getWindowsIfaceDNSsuffix(ifaces, ifacename) {
|
305 | let dnsSuffix = '';
|
306 |
|
307 | const interfaceName = ifacename + '.';
|
308 | try {
|
309 | const connectionDnsSuffix = ifaces.filter((iface) => {
|
310 | return interfaceName.includes(iface.name + '.');
|
311 | }).map((iface) => iface.dnsSuffix);
|
312 | if (connectionDnsSuffix[0]) {
|
313 | dnsSuffix = connectionDnsSuffix[0];
|
314 | }
|
315 | if (!dnsSuffix) dnsSuffix = '';
|
316 | return dnsSuffix;
|
317 | } catch (error) {
|
318 |
|
319 | return 'Unknown';
|
320 | }
|
321 | }
|
322 |
|
323 | function getWindowsWiredProfilesInformation() {
|
324 | try {
|
325 | const result = execSync('netsh lan show profiles', util.execOptsWin);
|
326 | const profileList = result.split('\r\nProfile on interface');
|
327 | return profileList;
|
328 | } catch (error) {
|
329 | if (error.status === 1 && error.stdout.includes('AutoConfig')) {
|
330 | return 'Disabled';
|
331 | }
|
332 | return [];
|
333 | }
|
334 | }
|
335 |
|
336 | function getWindowsWirelessIfaceSSID(interfaceName) {
|
337 | try {
|
338 | const result = execSync(`netsh wlan show interface name="${interfaceName}" | findstr "SSID"`, util.execOptsWin);
|
339 | const SSID = result.split('\r\n').shift();
|
340 | const parseSSID = SSID.split(':').pop();
|
341 | return parseSSID;
|
342 | } catch (error) {
|
343 | return 'Unknown';
|
344 | }
|
345 | }
|
346 | function getWindowsIEEE8021x(connectionType, iface, ifaces) {
|
347 | let i8021x = {
|
348 | state: 'Unknown',
|
349 | protocol: 'Unknown',
|
350 | };
|
351 |
|
352 | if (ifaces === 'Disabled') {
|
353 | i8021x.state = 'Disabled';
|
354 | i8021x.protocol = 'Not defined';
|
355 | return i8021x;
|
356 | }
|
357 |
|
358 | if (connectionType == 'wired' && ifaces.length > 0) {
|
359 | try {
|
360 |
|
361 | const iface8021xInfo = ifaces.find((element) => {
|
362 | return element.includes(iface + '\r\n');
|
363 | });
|
364 | const arrayIface8021xInfo = iface8021xInfo.split('\r\n');
|
365 | const state8021x = arrayIface8021xInfo.find((element) => {
|
366 | return element.includes('802.1x');
|
367 | });
|
368 |
|
369 | if (state8021x.includes('Disabled')) {
|
370 | i8021x.state = 'Disabled';
|
371 | i8021x.protocol = 'Not defined';
|
372 | } else if (state8021x.includes('Enabled')) {
|
373 | const protocol8021x = arrayIface8021xInfo.find((element) => {
|
374 | return element.includes('EAP');
|
375 | });
|
376 | i8021x.protocol = protocol8021x.split(':').pop();
|
377 | i8021x.state = 'Enabled';
|
378 | }
|
379 | } catch (error) {
|
380 |
|
381 | return i8021x;
|
382 | }
|
383 | } else if (connectionType == 'wireless') {
|
384 |
|
385 | let i8021xState = '';
|
386 | let i8021xProtocol = '';
|
387 |
|
388 |
|
389 |
|
390 | try {
|
391 | const SSID = getWindowsWirelessIfaceSSID(iface);
|
392 | if (SSID !== 'Unknown') {
|
393 | i8021xState = execSync(`netsh wlan show profiles "${SSID}" | findstr "802.1X"`, util.execOptsWin);
|
394 | i8021xProtocol = execSync(`netsh wlan show profiles "${SSID}" | findstr "EAP"`, util.execOptsWin);
|
395 | }
|
396 |
|
397 | if (i8021xState.includes(':') && i8021xProtocol.includes(':')) {
|
398 | i8021x.state = i8021xState.split(':').pop();
|
399 | i8021x.protocol = i8021xProtocol.split(':').pop();
|
400 | }
|
401 | } catch (error) {
|
402 |
|
403 | if (error.status === 1 && error.stdout.includes('AutoConfig')) {
|
404 | i8021x.state = 'Disabled';
|
405 | i8021x.protocol = 'Not defined';
|
406 | }
|
407 | return i8021x;
|
408 | }
|
409 | }
|
410 |
|
411 | return i8021x;
|
412 | }
|
413 |
|
414 | function splitSectionsNics(lines) {
|
415 | const result = [];
|
416 | let section = [];
|
417 | lines.forEach(function (line) {
|
418 | if (!line.startsWith('\t') && !line.startsWith(' ')) {
|
419 | if (section.length) {
|
420 | result.push(section);
|
421 | section = [];
|
422 | }
|
423 | }
|
424 | section.push(line);
|
425 | });
|
426 | if (section.length) {
|
427 | result.push(section);
|
428 | }
|
429 | return result;
|
430 | }
|
431 |
|
432 | function parseLinesDarwinNics(sections) {
|
433 | let nics = [];
|
434 | sections.forEach(section => {
|
435 | let nic = {
|
436 | iface: '',
|
437 | mtu: -1,
|
438 | mac: '',
|
439 | ip6: '',
|
440 | ip4: '',
|
441 | speed: -1,
|
442 | type: '',
|
443 | operstate: '',
|
444 | duplex: '',
|
445 | internal: false
|
446 | };
|
447 | const first = section[0];
|
448 | nic.iface = first.split(':')[0].trim();
|
449 | let parts = first.split('> mtu');
|
450 | nic.mtu = parts.length > 1 ? parseInt(parts[1], 10) : -1;
|
451 | if (isNaN(nic.mtu)) {
|
452 | nic.mtu = -1;
|
453 | }
|
454 | nic.internal = parts[0].toLowerCase().indexOf('loopback') > -1;
|
455 | section.forEach(line => {
|
456 | if (line.trim().startsWith('ether ')) {
|
457 | nic.mac = line.split('ether ')[1].toLowerCase().trim();
|
458 | }
|
459 | if (line.trim().startsWith('inet6 ') && !nic.ip6) {
|
460 | nic.ip6 = line.split('inet6 ')[1].toLowerCase().split('%')[0].split(' ')[0];
|
461 | }
|
462 | if (line.trim().startsWith('inet ') && !nic.ip4) {
|
463 | nic.ip4 = line.split('inet ')[1].toLowerCase().split(' ')[0];
|
464 | }
|
465 | });
|
466 | let speed = util.getValue(section, 'link rate');
|
467 | nic.speed = speed ? parseFloat(speed) : -1;
|
468 | if (nic.speed === -1) {
|
469 | speed = util.getValue(section, 'uplink rate');
|
470 | nic.speed = speed ? parseFloat(speed) : -1;
|
471 | if (nic.speed > -1 && speed.toLowerCase().indexOf('gbps') >= 0) {
|
472 | nic.speed = nic.speed * 1000;
|
473 | }
|
474 | } else {
|
475 | if (speed.toLowerCase().indexOf('gbps') >= 0) {
|
476 | nic.speed = nic.speed * 1000;
|
477 | }
|
478 | }
|
479 | nic.type = util.getValue(section, 'type').toLowerCase().indexOf('wi-fi') > -1 ? 'wireless' : 'wired';
|
480 | nic.operstate = util.getValue(section, 'status').toLowerCase().indexOf('active') > -1 ? 'up' : 'down';
|
481 | nic.duplex = util.getValue(section, 'media').toLowerCase().indexOf('half-duplex') > -1 ? 'half' : 'full';
|
482 | if (nic.ip6 || nic.ip4 || nic.mac) {
|
483 | nics.push(nic);
|
484 | }
|
485 | });
|
486 | return nics;
|
487 | }
|
488 |
|
489 | function getDarwinNics() {
|
490 | const cmd = '/sbin/ifconfig -v';
|
491 | try {
|
492 | const lines = execSync(cmd, { maxBuffer: 1024 * 20000 }).toString().split('\n');
|
493 | const nsections = splitSectionsNics(lines);
|
494 | return (parseLinesDarwinNics(nsections));
|
495 | } catch (e) {
|
496 | return [];
|
497 | }
|
498 | }
|
499 |
|
500 | function getLinuxIfaceConnectionName(interfaceName) {
|
501 | const cmd = `nmcli device status 2>/dev/null | grep ${interfaceName}`;
|
502 |
|
503 | try {
|
504 | const result = execSync(cmd).toString();
|
505 | const resultFormat = result.replace(/\s+/g, ' ').trim();
|
506 | const connectionNameLines = resultFormat.split(' ').slice(3);
|
507 | const connectionName = connectionNameLines.join(' ');
|
508 | return connectionName != '--' ? connectionName : '';
|
509 | } catch (e) {
|
510 | return '';
|
511 | }
|
512 | }
|
513 |
|
514 | function checkLinuxDCHPInterfaces(file) {
|
515 | let result = [];
|
516 | try {
|
517 | let cmd = `cat ${file} 2> /dev/null | grep 'iface\\|source'`;
|
518 | const lines = execSync(cmd, { maxBuffer: 1024 * 20000 }).toString().split('\n');
|
519 |
|
520 | lines.forEach(line => {
|
521 | const parts = line.replace(/\s+/g, ' ').trim().split(' ');
|
522 | if (parts.length >= 4) {
|
523 | if (line.toLowerCase().indexOf(' inet ') >= 0 && line.toLowerCase().indexOf('dhcp') >= 0) {
|
524 | result.push(parts[1]);
|
525 | }
|
526 | }
|
527 | if (line.toLowerCase().includes('source')) {
|
528 | let file = line.split(' ')[1];
|
529 | result = result.concat(checkLinuxDCHPInterfaces(file));
|
530 | }
|
531 | });
|
532 | } catch (e) {
|
533 | util.noop();
|
534 | }
|
535 | return result;
|
536 | }
|
537 |
|
538 | function getLinuxDHCPNics() {
|
539 |
|
540 | let cmd = 'ip a 2> /dev/null';
|
541 | let result = [];
|
542 | try {
|
543 | const lines = execSync(cmd, { maxBuffer: 1024 * 20000 }).toString().split('\n');
|
544 | const nsections = splitSectionsNics(lines);
|
545 | result = (parseLinuxDHCPNics(nsections));
|
546 | } catch (e) {
|
547 | util.noop();
|
548 | }
|
549 | try {
|
550 | result = checkLinuxDCHPInterfaces('/etc/network/interfaces');
|
551 | } catch (e) {
|
552 | util.noop();
|
553 | }
|
554 | return result;
|
555 | }
|
556 |
|
557 | function parseLinuxDHCPNics(sections) {
|
558 | const result = [];
|
559 | if (sections && sections.length) {
|
560 | sections.forEach(lines => {
|
561 | if (lines && lines.length) {
|
562 | const parts = lines[0].split(':');
|
563 | if (parts.length > 2) {
|
564 | for (let line of lines) {
|
565 | if (line.indexOf(' inet ') >= 0 && line.indexOf(' dynamic ') >= 0) {
|
566 | const parts2 = line.split(' ');
|
567 | const nic = parts2[parts2.length - 1].trim();
|
568 | result.push(nic);
|
569 | break;
|
570 | }
|
571 | }
|
572 | }
|
573 | }
|
574 | });
|
575 | }
|
576 | return result;
|
577 | }
|
578 |
|
579 | function getLinuxIfaceDHCPstatus(iface, connectionName, DHCPNics) {
|
580 | let result = false;
|
581 | if (connectionName) {
|
582 | const cmd = `nmcli connection show "${connectionName}" 2>/dev/null \| grep ipv4.method;`;
|
583 | try {
|
584 | const lines = execSync(cmd).toString();
|
585 | const resultFormat = lines.replace(/\s+/g, ' ').trim();
|
586 |
|
587 | let dhcStatus = resultFormat.split(' ').slice(1).toString();
|
588 | switch (dhcStatus) {
|
589 | case 'auto':
|
590 | result = true;
|
591 | break;
|
592 |
|
593 | default:
|
594 | result = false;
|
595 | break;
|
596 | }
|
597 | return result;
|
598 | } catch (e) {
|
599 | return (DHCPNics.indexOf(iface) >= 0);
|
600 | }
|
601 | } else {
|
602 | return (DHCPNics.indexOf(iface) >= 0);
|
603 | }
|
604 | }
|
605 |
|
606 | function getDarwinIfaceDHCPstatus(iface) {
|
607 | let result = false;
|
608 | const cmd = `ipconfig getpacket "${iface}" 2>/dev/null \| grep lease_time;`;
|
609 | try {
|
610 | const lines = execSync(cmd).toString().split('\n');
|
611 | if (lines.length && lines[0].startsWith('lease_time')) {
|
612 | result = true;
|
613 | }
|
614 | } catch (e) {
|
615 | util.noop();
|
616 | }
|
617 | return result;
|
618 | }
|
619 |
|
620 | function getLinuxIfaceDNSsuffix(connectionName) {
|
621 | if (connectionName) {
|
622 | const cmd = `nmcli connection show "${connectionName}" 2>/dev/null \| grep ipv4.dns-search;`;
|
623 | try {
|
624 | const result = execSync(cmd).toString();
|
625 | const resultFormat = result.replace(/\s+/g, ' ').trim();
|
626 | const dnsSuffix = resultFormat.split(' ').slice(1).toString();
|
627 | return dnsSuffix == '--' ? 'Not defined' : dnsSuffix;
|
628 | } catch (e) {
|
629 | return 'Unknown';
|
630 | }
|
631 | } else {
|
632 | return 'Unknown';
|
633 | }
|
634 | }
|
635 |
|
636 | function getLinuxIfaceIEEE8021xAuth(connectionName) {
|
637 | if (connectionName) {
|
638 | const cmd = `nmcli connection show "${connectionName}" 2>/dev/null \| grep 802-1x.eap;`;
|
639 | try {
|
640 | const result = execSync(cmd).toString();
|
641 | const resultFormat = result.replace(/\s+/g, ' ').trim();
|
642 | const authenticationProtocol = resultFormat.split(' ').slice(1).toString();
|
643 |
|
644 |
|
645 | return authenticationProtocol == '--' ? '' : authenticationProtocol;
|
646 | } catch (e) {
|
647 | return 'Not defined';
|
648 | }
|
649 | } else {
|
650 | return 'Not defined';
|
651 | }
|
652 | }
|
653 |
|
654 | function getLinuxIfaceIEEE8021xState(authenticationProtocol) {
|
655 | if (authenticationProtocol) {
|
656 | if (authenticationProtocol == 'Not defined') {
|
657 | return 'Disabled';
|
658 | }
|
659 | return 'Enabled';
|
660 | } else {
|
661 | return 'Unknown';
|
662 | }
|
663 | }
|
664 |
|
665 | function testVirtualNic(iface, ifaceName, mac) {
|
666 | const virtualMacs = ['00:00:00:00:00:00', '00:03:FF', '00:05:69', '00:0C:29', '00:0F:4B', '00:0F:4B', '00:13:07', '00:13:BE', '00:15:5d', '00:16:3E', '00:1C:42', '00:21:F6', '00:21:F6', '00:24:0B', '00:24:0B', '00:50:56', '00:A0:B1', '00:E0:C8', '08:00:27', '0A:00:27', '18:92:2C', '16:DF:49', '3C:F3:92', '54:52:00', 'FC:15:97'];
|
667 | if (mac) {
|
668 | return virtualMacs.filter(item => { return mac.toUpperCase().toUpperCase().startsWith(item.substr(0, mac.length)); }).length > 0 ||
|
669 | iface.toLowerCase().indexOf(' virtual ') > -1 ||
|
670 | ifaceName.toLowerCase().indexOf(' virtual ') > -1 ||
|
671 | iface.toLowerCase().indexOf('vethernet ') > -1 ||
|
672 | ifaceName.toLowerCase().indexOf('vethernet ') > -1 ||
|
673 | iface.toLowerCase().startsWith('veth') ||
|
674 | ifaceName.toLowerCase().startsWith('veth') ||
|
675 | iface.toLowerCase().startsWith('vboxnet') ||
|
676 | ifaceName.toLowerCase().startsWith('vboxnet');
|
677 | } else return false;
|
678 | }
|
679 |
|
680 | function networkInterfaces(callback, rescan = true) {
|
681 |
|
682 | if (typeof callback === 'boolean') {
|
683 | rescan = callback;
|
684 | callback = null;
|
685 | }
|
686 | return new Promise((resolve) => {
|
687 | process.nextTick(() => {
|
688 | let ifaces = os.networkInterfaces();
|
689 |
|
690 | let result = [];
|
691 | let nics = [];
|
692 | let dnsSuffixes = [];
|
693 | let nics8021xInfo = [];
|
694 |
|
695 | if (_darwin || _freebsd || _openbsd || _netbsd) {
|
696 | nics = getDarwinNics();
|
697 |
|
698 |
|
699 | nics.forEach(nic => {
|
700 |
|
701 | if ({}.hasOwnProperty.call(ifaces, nic.iface)) {
|
702 | ifaces[nic.iface].forEach(function (details) {
|
703 | if (details.family === 'IPv4') {
|
704 | nic.ip4subnet = details.netmask;
|
705 | }
|
706 | if (details.family === 'IPv6') {
|
707 | nic.ip6subnet = details.netmask;
|
708 | }
|
709 | });
|
710 | }
|
711 |
|
712 | result.push({
|
713 | iface: nic.iface,
|
714 | ifaceName: nic.iface,
|
715 | ip4: nic.ip4,
|
716 | ip4subnet: nic.ip4subnet || '',
|
717 | ip6: nic.ip6,
|
718 | ip6subnet: nic.ip6subnet || '',
|
719 | mac: nic.mac,
|
720 | internal: nic.internal,
|
721 | virtual: nic.internal ? false : testVirtualNic(nic.iface, nic.iface, nic.mac),
|
722 | operstate: nic.operstate,
|
723 | type: nic.type,
|
724 | duplex: nic.duplex,
|
725 | mtu: nic.mtu,
|
726 | speed: nic.speed,
|
727 | dhcp: getDarwinIfaceDHCPstatus(nic.iface),
|
728 | dnsSuffix: '',
|
729 | ieee8021xAuth: '',
|
730 | ieee8021xState: '',
|
731 | carrierChanges: 0
|
732 | });
|
733 | });
|
734 | _networkInterfaces = result;
|
735 | if (callback) { callback(result); }
|
736 | resolve(result);
|
737 | } else {
|
738 | if ((JSON.stringify(ifaces) === JSON.stringify(_ifaces)) && !rescan) {
|
739 |
|
740 | result = _networkInterfaces;
|
741 |
|
742 | if (callback) { callback(result); }
|
743 | resolve(result);
|
744 | } else {
|
745 | _ifaces = Object.assign({}, ifaces);
|
746 |
|
747 | if (_windows) {
|
748 | nics = getWindowsNics();
|
749 | nics.forEach(nic => {
|
750 | let found = false;
|
751 | Object.keys(ifaces).forEach(key => {
|
752 | if (!found) {
|
753 | ifaces[key].forEach(value => {
|
754 | if (Object.keys(value).indexOf('mac') >= 0) {
|
755 | found = value['mac'] === nic.mac;
|
756 | }
|
757 | });
|
758 | }
|
759 | });
|
760 |
|
761 | if (!found) {
|
762 | ifaces[nic.name] = [{ mac: nic.mac }];
|
763 | }
|
764 | });
|
765 |
|
766 | nics8021xInfo = getWindowsWiredProfilesInformation();
|
767 | dnsSuffixes = getWindowsDNSsuffixes();
|
768 | }
|
769 | if (_linux) {
|
770 | _dhcpNics = getLinuxDHCPNics();
|
771 | }
|
772 | for (let dev in ifaces) {
|
773 | let ip4 = '';
|
774 | let ip4subnet = '';
|
775 | let ip6 = '';
|
776 | let ip6subnet = '';
|
777 | let mac = '';
|
778 | let duplex = '';
|
779 | let mtu = '';
|
780 | let speed = -1;
|
781 | let carrierChanges = 0;
|
782 | let operstate = 'down';
|
783 | let dhcp = false;
|
784 | let dnsSuffix = '';
|
785 | let ieee8021xAuth = '';
|
786 | let ieee8021xState = '';
|
787 | let type = '';
|
788 |
|
789 | if ({}.hasOwnProperty.call(ifaces, dev)) {
|
790 | let ifaceName = dev;
|
791 | ifaces[dev].forEach(function (details) {
|
792 | if (details.family === 'IPv4') {
|
793 | ip4 = details.address;
|
794 | ip4subnet = details.netmask;
|
795 | }
|
796 | if (details.family === 'IPv6') {
|
797 | if (!ip6 || ip6.match(/^fe80::/i)) {
|
798 | ip6 = details.address;
|
799 | ip6subnet = details.netmask;
|
800 | }
|
801 | }
|
802 | mac = details.mac;
|
803 |
|
804 | if (mac.indexOf('00:00:0') > -1 && (_linux || _darwin) && parseInt(process.versions.node.split('.'), 10) === 8) {
|
805 | if (Object.keys(_mac).length === 0) {
|
806 | _mac = getMacAddresses();
|
807 | }
|
808 | mac = _mac[dev] || '';
|
809 | }
|
810 | });
|
811 | if (_linux) {
|
812 | let iface = dev.split(':')[0].trim().toLowerCase();
|
813 | const cmd = `echo -n "addr_assign_type: "; cat /sys/class/net/${iface}/addr_assign_type 2>/dev/null; echo;
|
814 | echo -n "address: "; cat /sys/class/net/${iface}/address 2>/dev/null; echo;
|
815 | echo -n "addr_len: "; cat /sys/class/net/${iface}/addr_len 2>/dev/null; echo;
|
816 | echo -n "broadcast: "; cat /sys/class/net/${iface}/broadcast 2>/dev/null; echo;
|
817 | echo -n "carrier: "; cat /sys/class/net/${iface}/carrier 2>/dev/null; echo;
|
818 | echo -n "carrier_changes: "; cat /sys/class/net/${iface}/carrier_changes 2>/dev/null; echo;
|
819 | echo -n "dev_id: "; cat /sys/class/net/${iface}/dev_id 2>/dev/null; echo;
|
820 | echo -n "dev_port: "; cat /sys/class/net/${iface}/dev_port 2>/dev/null; echo;
|
821 | echo -n "dormant: "; cat /sys/class/net/${iface}/dormant 2>/dev/null; echo;
|
822 | echo -n "duplex: "; cat /sys/class/net/${iface}/duplex 2>/dev/null; echo;
|
823 | echo -n "flags: "; cat /sys/class/net/${iface}/flags 2>/dev/null; echo;
|
824 | echo -n "gro_flush_timeout: "; cat /sys/class/net/${iface}/gro_flush_timeout 2>/dev/null; echo;
|
825 | echo -n "ifalias: "; cat /sys/class/net/${iface}/ifalias 2>/dev/null; echo;
|
826 | echo -n "ifindex: "; cat /sys/class/net/${iface}/ifindex 2>/dev/null; echo;
|
827 | echo -n "iflink: "; cat /sys/class/net/${iface}/iflink 2>/dev/null; echo;
|
828 | echo -n "link_mode: "; cat /sys/class/net/${iface}/link_mode 2>/dev/null; echo;
|
829 | echo -n "mtu: "; cat /sys/class/net/${iface}/mtu 2>/dev/null; echo;
|
830 | echo -n "netdev_group: "; cat /sys/class/net/${iface}/netdev_group 2>/dev/null; echo;
|
831 | echo -n "operstate: "; cat /sys/class/net/${iface}/operstate 2>/dev/null; echo;
|
832 | echo -n "proto_down: "; cat /sys/class/net/${iface}/proto_down 2>/dev/null; echo;
|
833 | echo -n "speed: "; cat /sys/class/net/${iface}/speed 2>/dev/null; echo;
|
834 | echo -n "tx_queue_len: "; cat /sys/class/net/${iface}/tx_queue_len 2>/dev/null; echo;
|
835 | echo -n "type: "; cat /sys/class/net/${iface}/type 2>/dev/null; echo;
|
836 | echo -n "wireless: "; cat /proc/net/wireless 2>/dev/null \| grep ${iface}; echo;
|
837 | echo -n "wirelessspeed: "; iw dev ${iface} link 2>&1 \| grep bitrate; echo;`;
|
838 |
|
839 | let lines = [];
|
840 | try {
|
841 | lines = execSync(cmd).toString().split('\n');
|
842 | const connectionName = getLinuxIfaceConnectionName(iface);
|
843 | dhcp = getLinuxIfaceDHCPstatus(iface, connectionName, _dhcpNics);
|
844 | dnsSuffix = getLinuxIfaceDNSsuffix(connectionName);
|
845 | ieee8021xAuth = getLinuxIfaceIEEE8021xAuth(connectionName);
|
846 | ieee8021xState = getLinuxIfaceIEEE8021xState(ieee8021xAuth);
|
847 | } catch (e) {
|
848 | util.noop();
|
849 | }
|
850 | duplex = util.getValue(lines, 'duplex');
|
851 | duplex = duplex.startsWith('cat') ? '' : duplex;
|
852 | mtu = parseInt(util.getValue(lines, 'mtu'), 10);
|
853 | let myspeed = parseInt(util.getValue(lines, 'speed'), 10);
|
854 | speed = isNaN(myspeed) ? -1 : myspeed;
|
855 | let wirelessspeed = util.getValue(lines, 'wirelessspeed').split('tx bitrate: ');
|
856 | if (speed === -1 && wirelessspeed.length === 2) {
|
857 | myspeed = parseFloat(wirelessspeed[1]);
|
858 | speed = isNaN(myspeed) ? -1 : myspeed;
|
859 | }
|
860 | carrierChanges = parseInt(util.getValue(lines, 'carrier_changes'), 10);
|
861 | operstate = util.getValue(lines, 'operstate');
|
862 | type = operstate === 'up' ? (util.getValue(lines, 'wireless').trim() ? 'wireless' : 'wired') : 'unknown';
|
863 | if (iface === 'lo' || iface.startsWith('bond')) { type = 'virtual'; }
|
864 | }
|
865 | if (_windows) {
|
866 |
|
867 |
|
868 | dnsSuffix = getWindowsIfaceDNSsuffix(dnsSuffixes.ifaces, dev);
|
869 | nics.forEach(detail => {
|
870 | if (detail.mac === mac) {
|
871 | ifaceName = detail.name;
|
872 | dhcp = detail.dhcp;
|
873 | operstate = detail.operstate;
|
874 | speed = detail.speed;
|
875 | type = detail.type;
|
876 | }
|
877 | });
|
878 |
|
879 | if (dev.toLowerCase().indexOf('wlan') >= 0 || ifaceName.toLowerCase().indexOf('wlan') >= 0 || ifaceName.toLowerCase().indexOf('802.11n') >= 0 || ifaceName.toLowerCase().indexOf('wireless') >= 0 || ifaceName.toLowerCase().indexOf('wi-fi') >= 0 || ifaceName.toLowerCase().indexOf('wifi') >= 0) {
|
880 | type = 'wireless';
|
881 | }
|
882 |
|
883 | const IEEE8021x = getWindowsIEEE8021x(type, dev, nics8021xInfo);
|
884 | ieee8021xAuth = IEEE8021x.protocol;
|
885 | ieee8021xState = IEEE8021x.state;
|
886 | }
|
887 | let internal = (ifaces[dev] && ifaces[dev][0]) ? ifaces[dev][0].internal : false;
|
888 | if (dev.toLowerCase().indexOf('loopback') > -1 || ifaceName.toLowerCase().indexOf('loopback') > -1) {
|
889 | internal = true;
|
890 | }
|
891 | const virtual = internal ? false : testVirtualNic(dev, ifaceName, mac);
|
892 | result.push({
|
893 | iface: dev,
|
894 | ifaceName,
|
895 | ip4,
|
896 | ip4subnet,
|
897 | ip6,
|
898 | ip6subnet,
|
899 | mac,
|
900 | internal,
|
901 | virtual,
|
902 | operstate,
|
903 | type,
|
904 | duplex,
|
905 | mtu,
|
906 | speed,
|
907 | dhcp,
|
908 | dnsSuffix,
|
909 | ieee8021xAuth,
|
910 | ieee8021xState,
|
911 | carrierChanges,
|
912 | });
|
913 | }
|
914 | }
|
915 | _networkInterfaces = result;
|
916 | if (callback) { callback(result); }
|
917 | resolve(result);
|
918 | }
|
919 | }
|
920 | });
|
921 | });
|
922 | }
|
923 |
|
924 | exports.networkInterfaces = networkInterfaces;
|
925 |
|
926 |
|
927 |
|
928 |
|
929 | function calcNetworkSpeed(iface, rx_bytes, tx_bytes, operstate, rx_dropped, rx_errors, tx_dropped, tx_errors) {
|
930 | let result = {
|
931 | iface,
|
932 | operstate,
|
933 | rx_bytes,
|
934 | rx_dropped,
|
935 | rx_errors,
|
936 | tx_bytes,
|
937 | tx_dropped,
|
938 | tx_errors,
|
939 | rx_sec: -1,
|
940 | tx_sec: -1,
|
941 | ms: 0
|
942 | };
|
943 |
|
944 | if (_network[iface] && _network[iface].ms) {
|
945 | result.ms = Date.now() - _network[iface].ms;
|
946 | result.rx_sec = (rx_bytes - _network[iface].rx_bytes) >= 0 ? (rx_bytes - _network[iface].rx_bytes) / (result.ms / 1000) : 0;
|
947 | result.tx_sec = (tx_bytes - _network[iface].tx_bytes) >= 0 ? (tx_bytes - _network[iface].tx_bytes) / (result.ms / 1000) : 0;
|
948 | _network[iface].rx_bytes = rx_bytes;
|
949 | _network[iface].tx_bytes = tx_bytes;
|
950 | _network[iface].rx_sec = result.rx_sec;
|
951 | _network[iface].tx_sec = result.tx_sec;
|
952 | _network[iface].ms = Date.now();
|
953 | _network[iface].last_ms = result.ms;
|
954 | _network[iface].operstate = operstate;
|
955 | } else {
|
956 | if (!_network[iface]) _network[iface] = {};
|
957 | _network[iface].rx_bytes = rx_bytes;
|
958 | _network[iface].tx_bytes = tx_bytes;
|
959 | _network[iface].rx_sec = -1;
|
960 | _network[iface].tx_sec = -1;
|
961 | _network[iface].ms = Date.now();
|
962 | _network[iface].last_ms = 0;
|
963 | _network[iface].operstate = operstate;
|
964 | }
|
965 | return result;
|
966 | }
|
967 |
|
968 | function networkStats(ifaces, callback) {
|
969 |
|
970 | let ifacesArray = [];
|
971 |
|
972 | if (util.isFunction(ifaces) && !callback) {
|
973 | callback = ifaces;
|
974 | ifacesArray = [getDefaultNetworkInterface()];
|
975 | } else {
|
976 | ifaces = ifaces || getDefaultNetworkInterface();
|
977 | ifaces = ifaces.trim().toLowerCase().replace(/,+/g, '|');
|
978 | ifacesArray = ifaces.split('|');
|
979 | }
|
980 |
|
981 | return new Promise((resolve) => {
|
982 | process.nextTick(() => {
|
983 |
|
984 | const result = [];
|
985 |
|
986 | const workload = [];
|
987 | if (ifacesArray.length && ifacesArray[0].trim() === '*') {
|
988 | ifacesArray = [];
|
989 | networkInterfaces(false).then(allIFaces => {
|
990 | for (let iface of allIFaces) {
|
991 | ifacesArray.push(iface.iface);
|
992 | }
|
993 | networkStats(ifacesArray.join(',')).then(result => {
|
994 | if (callback) { callback(result); }
|
995 | resolve(result);
|
996 | });
|
997 | });
|
998 | } else {
|
999 | for (let iface of ifacesArray) {
|
1000 | workload.push(networkStatsSingle(iface.trim()));
|
1001 | }
|
1002 | if (workload.length) {
|
1003 | Promise.all(
|
1004 | workload
|
1005 | ).then(data => {
|
1006 | if (callback) { callback(data); }
|
1007 | resolve(data);
|
1008 | });
|
1009 | } else {
|
1010 | if (callback) { callback(result); }
|
1011 | resolve(result);
|
1012 | }
|
1013 | }
|
1014 | });
|
1015 | });
|
1016 | }
|
1017 |
|
1018 | function networkStatsSingle(iface) {
|
1019 |
|
1020 | function parseLinesWindowsPerfData(sections) {
|
1021 | let perfData = [];
|
1022 | for (let i in sections) {
|
1023 | if ({}.hasOwnProperty.call(sections, i)) {
|
1024 | if (sections[i].trim() !== '') {
|
1025 | let lines = sections[i].trim().split('\r\n');
|
1026 | perfData.push({
|
1027 | name: util.getValue(lines, 'Name', '=').replace(/[()\[\] ]+/g, '').replace('#', '_').toLowerCase(),
|
1028 | rx_bytes: parseInt(util.getValue(lines, 'BytesReceivedPersec', '='), 10),
|
1029 | rx_errors: parseInt(util.getValue(lines, 'PacketsReceivedErrors', '='), 10),
|
1030 | rx_dropped: parseInt(util.getValue(lines, 'PacketsReceivedDiscarded', '='), 10),
|
1031 | tx_bytes: parseInt(util.getValue(lines, 'BytesSentPersec', '='), 10),
|
1032 | tx_errors: parseInt(util.getValue(lines, 'PacketsOutboundErrors', '='), 10),
|
1033 | tx_dropped: parseInt(util.getValue(lines, 'PacketsOutboundDiscarded', '='), 10)
|
1034 | });
|
1035 | }
|
1036 | }
|
1037 | }
|
1038 | return perfData;
|
1039 | }
|
1040 |
|
1041 | return new Promise((resolve) => {
|
1042 | process.nextTick(() => {
|
1043 |
|
1044 | const ifaceSanitized = util.sanitizeShellString(iface);
|
1045 |
|
1046 | let result = {
|
1047 | iface: ifaceSanitized,
|
1048 | operstate: 'unknown',
|
1049 | rx_bytes: 0,
|
1050 | rx_dropped: 0,
|
1051 | rx_errors: 0,
|
1052 | tx_bytes: 0,
|
1053 | tx_dropped: 0,
|
1054 | tx_errors: 0,
|
1055 | rx_sec: -1,
|
1056 | tx_sec: -1,
|
1057 | ms: 0
|
1058 | };
|
1059 |
|
1060 | let operstate = 'unknown';
|
1061 | let rx_bytes = 0;
|
1062 | let tx_bytes = 0;
|
1063 | let rx_dropped = 0;
|
1064 | let rx_errors = 0;
|
1065 | let tx_dropped = 0;
|
1066 | let tx_errors = 0;
|
1067 |
|
1068 | let cmd, lines, stats;
|
1069 | if (!_network[ifaceSanitized] || (_network[ifaceSanitized] && !_network[ifaceSanitized].ms) || (_network[ifaceSanitized] && _network[ifaceSanitized].ms && Date.now() - _network[ifaceSanitized].ms >= 500)) {
|
1070 | if (_linux) {
|
1071 | if (fs.existsSync('/sys/class/net/' + ifaceSanitized)) {
|
1072 | cmd =
|
1073 | 'cat /sys/class/net/' + ifaceSanitized + '/operstate; ' +
|
1074 | 'cat /sys/class/net/' + ifaceSanitized + '/statistics/rx_bytes; ' +
|
1075 | 'cat /sys/class/net/' + ifaceSanitized + '/statistics/tx_bytes; ' +
|
1076 | 'cat /sys/class/net/' + ifaceSanitized + '/statistics/rx_dropped; ' +
|
1077 | 'cat /sys/class/net/' + ifaceSanitized + '/statistics/rx_errors; ' +
|
1078 | 'cat /sys/class/net/' + ifaceSanitized + '/statistics/tx_dropped; ' +
|
1079 | 'cat /sys/class/net/' + ifaceSanitized + '/statistics/tx_errors; ';
|
1080 | exec(cmd, function (error, stdout) {
|
1081 | if (!error) {
|
1082 | lines = stdout.toString().split('\n');
|
1083 | operstate = lines[0].trim();
|
1084 | rx_bytes = parseInt(lines[1], 10);
|
1085 | tx_bytes = parseInt(lines[2], 10);
|
1086 | rx_dropped = parseInt(lines[3], 10);
|
1087 | rx_errors = parseInt(lines[4], 10);
|
1088 | tx_dropped = parseInt(lines[5], 10);
|
1089 | tx_errors = parseInt(lines[6], 10);
|
1090 |
|
1091 | result = calcNetworkSpeed(ifaceSanitized, rx_bytes, tx_bytes, operstate, rx_dropped, rx_errors, tx_dropped, tx_errors);
|
1092 |
|
1093 | }
|
1094 | resolve(result);
|
1095 | });
|
1096 | } else {
|
1097 | resolve(result);
|
1098 | }
|
1099 | }
|
1100 | if (_freebsd || _openbsd || _netbsd) {
|
1101 | cmd = 'netstat -ibndI ' + ifaceSanitized;
|
1102 | exec(cmd, function (error, stdout) {
|
1103 | if (!error) {
|
1104 | lines = stdout.toString().split('\n');
|
1105 | for (let i = 1; i < lines.length; i++) {
|
1106 | const line = lines[i].replace(/ +/g, ' ').split(' ');
|
1107 | if (line && line[0] && line[7] && line[10]) {
|
1108 | rx_bytes = rx_bytes + parseInt(line[7]);
|
1109 | if (line[6].trim() !== '-') { rx_dropped = rx_dropped + parseInt(line[6]); }
|
1110 | if (line[5].trim() !== '-') { rx_errors = rx_errors + parseInt(line[5]); }
|
1111 | tx_bytes = tx_bytes + parseInt(line[10]);
|
1112 | if (line[12].trim() !== '-') { tx_dropped = tx_dropped + parseInt(line[12]); }
|
1113 | if (line[9].trim() !== '-') { tx_errors = tx_errors + parseInt(line[9]); }
|
1114 | operstate = 'up';
|
1115 | }
|
1116 | }
|
1117 | result = calcNetworkSpeed(ifaceSanitized, rx_bytes, tx_bytes, operstate, rx_dropped, rx_errors, tx_dropped, tx_errors);
|
1118 | }
|
1119 | resolve(result);
|
1120 | });
|
1121 | }
|
1122 | if (_darwin) {
|
1123 | cmd = 'ifconfig ' + ifaceSanitized + ' | grep "status"';
|
1124 | exec(cmd, function (error, stdout) {
|
1125 | result.operstate = (stdout.toString().split(':')[1] || '').trim();
|
1126 | result.operstate = (result.operstate || '').toLowerCase();
|
1127 | result.operstate = (result.operstate === 'active' ? 'up' : (result.operstate === 'inactive' ? 'down' : 'unknown'));
|
1128 | cmd = 'netstat -bdI ' + ifaceSanitized;
|
1129 | exec(cmd, function (error, stdout) {
|
1130 | if (!error) {
|
1131 | lines = stdout.toString().split('\n');
|
1132 |
|
1133 | if (lines.length > 1 && lines[1].trim() !== '') {
|
1134 |
|
1135 |
|
1136 | stats = lines[1].replace(/ +/g, ' ').split(' ');
|
1137 | rx_bytes = parseInt(stats[6]);
|
1138 | rx_dropped = parseInt(stats[11]);
|
1139 | rx_errors = parseInt(stats[5]);
|
1140 | tx_bytes = parseInt(stats[9]);
|
1141 | tx_dropped = parseInt(stats[11]);
|
1142 | tx_errors = parseInt(stats[8]);
|
1143 |
|
1144 | result = calcNetworkSpeed(ifaceSanitized, rx_bytes, tx_bytes, result.operstate, rx_dropped, rx_errors, tx_dropped, tx_errors);
|
1145 | }
|
1146 | }
|
1147 | resolve(result);
|
1148 | });
|
1149 | });
|
1150 | }
|
1151 | if (_windows) {
|
1152 | let perfData = [];
|
1153 | let ifaceName = ifaceSanitized;
|
1154 |
|
1155 |
|
1156 | util.wmic('path Win32_PerfRawData_Tcpip_NetworkInterface Get name,BytesReceivedPersec,BytesSentPersec,BytesTotalPersec,PacketsOutboundDiscarded,PacketsOutboundErrors,PacketsReceivedDiscarded,PacketsReceivedErrors /value').then((stdout, error) => {
|
1157 | if (!error) {
|
1158 | const psections = stdout.toString().split(/\n\s*\n/);
|
1159 | perfData = parseLinesWindowsPerfData(psections);
|
1160 | }
|
1161 |
|
1162 |
|
1163 | networkInterfaces(false).then(interfaces => {
|
1164 |
|
1165 | rx_bytes = 0;
|
1166 | tx_bytes = 0;
|
1167 | perfData.forEach(detail => {
|
1168 | interfaces.forEach(det => {
|
1169 | if ((det.iface.toLowerCase() === ifaceSanitized.toLowerCase() ||
|
1170 | det.mac.toLowerCase() === ifaceSanitized.toLowerCase() ||
|
1171 | det.ip4.toLowerCase() === ifaceSanitized.toLowerCase() ||
|
1172 | det.ip6.toLowerCase() === ifaceSanitized.toLowerCase() ||
|
1173 | det.ifaceName.replace(/[()\[\] ]+/g, '').replace('#', '_').toLowerCase() === ifaceSanitized.replace(/[()\[\] ]+/g, '').replace('#', '_').toLowerCase()) &&
|
1174 | (det.ifaceName.replace(/[()\[\] ]+/g, '').replace('#', '_').toLowerCase() === detail.name)) {
|
1175 | ifaceName = det.iface;
|
1176 | rx_bytes = detail.rx_bytes;
|
1177 | rx_dropped = detail.rx_dropped;
|
1178 | rx_errors = detail.rx_errors;
|
1179 | tx_bytes = detail.tx_bytes;
|
1180 | tx_dropped = detail.tx_dropped;
|
1181 | tx_errors = detail.tx_errors;
|
1182 | operstate = det.operstate;
|
1183 | }
|
1184 | });
|
1185 | });
|
1186 | if (rx_bytes && tx_bytes) {
|
1187 | result = calcNetworkSpeed(ifaceName, parseInt(rx_bytes), parseInt(tx_bytes), operstate, rx_dropped, rx_errors, tx_dropped, tx_errors);
|
1188 | }
|
1189 | resolve(result);
|
1190 | });
|
1191 | });
|
1192 | }
|
1193 | } else {
|
1194 | result.rx_bytes = _network[ifaceSanitized].rx_bytes;
|
1195 | result.tx_bytes = _network[ifaceSanitized].tx_bytes;
|
1196 | result.rx_sec = _network[ifaceSanitized].rx_sec;
|
1197 | result.tx_sec = _network[ifaceSanitized].tx_sec;
|
1198 | result.ms = _network[ifaceSanitized].last_ms;
|
1199 | result.operstate = _network[ifaceSanitized].operstate;
|
1200 | resolve(result);
|
1201 | }
|
1202 | });
|
1203 | });
|
1204 | }
|
1205 |
|
1206 | exports.networkStats = networkStats;
|
1207 |
|
1208 |
|
1209 |
|
1210 |
|
1211 | function networkConnections(callback) {
|
1212 |
|
1213 | return new Promise((resolve) => {
|
1214 | process.nextTick(() => {
|
1215 | let result = [];
|
1216 | if (_linux || _freebsd || _openbsd || _netbsd) {
|
1217 | let cmd = 'export LC_ALL=C; netstat -tunap | grep "ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN"; unset LC_ALL';
|
1218 | if (_freebsd || _openbsd || _netbsd) cmd = 'export LC_ALL=C; netstat -na | grep "ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN"; unset LC_ALL';
|
1219 | exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
|
1220 | let lines = stdout.toString().split('\n');
|
1221 | if (!error && (lines.length > 1 || lines[0] != '')) {
|
1222 | lines.forEach(function (line) {
|
1223 | line = line.replace(/ +/g, ' ').split(' ');
|
1224 | if (line.length >= 7) {
|
1225 | let localip = line[3];
|
1226 | let localport = '';
|
1227 | let localaddress = line[3].split(':');
|
1228 | if (localaddress.length > 1) {
|
1229 | localport = localaddress[localaddress.length - 1];
|
1230 | localaddress.pop();
|
1231 | localip = localaddress.join(':');
|
1232 | }
|
1233 | let peerip = line[4];
|
1234 | let peerport = '';
|
1235 | let peeraddress = line[4].split(':');
|
1236 | if (peeraddress.length > 1) {
|
1237 | peerport = peeraddress[peeraddress.length - 1];
|
1238 | peeraddress.pop();
|
1239 | peerip = peeraddress.join(':');
|
1240 | }
|
1241 | let connstate = line[5];
|
1242 |
|
1243 | let proc = line[6].split('/');
|
1244 |
|
1245 | if (connstate) {
|
1246 | result.push({
|
1247 | protocol: line[0],
|
1248 | localaddress: localip,
|
1249 | localport: localport,
|
1250 | peeraddress: peerip,
|
1251 | peerport: peerport,
|
1252 | state: connstate,
|
1253 | pid: proc[0] && proc[0] !== '-' ? parseInt(proc[0], 10) : -1,
|
1254 | process: proc[1] ? proc[1].split(' ')[0] : ''
|
1255 | });
|
1256 | }
|
1257 | }
|
1258 | });
|
1259 | if (callback) {
|
1260 | callback(result);
|
1261 | }
|
1262 | resolve(result);
|
1263 | } else {
|
1264 | cmd = 'ss -tunap | grep "ESTAB\\|SYN-SENT\\|SYN-RECV\\|FIN-WAIT1\\|FIN-WAIT2\\|TIME-WAIT\\|CLOSE\\|CLOSE-WAIT\\|LAST-ACK\\|LISTEN\\|CLOSING"';
|
1265 | exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
|
1266 |
|
1267 | if (!error) {
|
1268 | let lines = stdout.toString().split('\n');
|
1269 | lines.forEach(function (line) {
|
1270 | line = line.replace(/ +/g, ' ').split(' ');
|
1271 | if (line.length >= 6) {
|
1272 | let localip = line[4];
|
1273 | let localport = '';
|
1274 | let localaddress = line[4].split(':');
|
1275 | if (localaddress.length > 1) {
|
1276 | localport = localaddress[localaddress.length - 1];
|
1277 | localaddress.pop();
|
1278 | localip = localaddress.join(':');
|
1279 | }
|
1280 | let peerip = line[5];
|
1281 | let peerport = '';
|
1282 | let peeraddress = line[5].split(':');
|
1283 | if (peeraddress.length > 1) {
|
1284 | peerport = peeraddress[peeraddress.length - 1];
|
1285 | peeraddress.pop();
|
1286 | peerip = peeraddress.join(':');
|
1287 | }
|
1288 | let connstate = line[1];
|
1289 | if (connstate === 'ESTAB') connstate = 'ESTABLISHED';
|
1290 | if (connstate === 'TIME-WAIT') connstate = 'TIME_WAIT';
|
1291 | let pid = -1;
|
1292 | let process = '';
|
1293 | if (line.length >= 7 && line[6].indexOf('users:') > -1) {
|
1294 | let proc = line[6].replace('users:(("', '').replace(/"/g, '').split(',');
|
1295 | if (proc.length > 2) {
|
1296 | process = proc[0].split(' ')[0];
|
1297 | pid = parseInt(proc[1], 10);
|
1298 | }
|
1299 | }
|
1300 | if (connstate) {
|
1301 | result.push({
|
1302 | protocol: line[0],
|
1303 | localaddress: localip,
|
1304 | localport: localport,
|
1305 | peeraddress: peerip,
|
1306 | peerport: peerport,
|
1307 | state: connstate,
|
1308 | pid,
|
1309 | process
|
1310 | });
|
1311 | }
|
1312 | }
|
1313 | });
|
1314 | }
|
1315 | if (callback) {
|
1316 | callback(result);
|
1317 | }
|
1318 | resolve(result);
|
1319 | });
|
1320 | }
|
1321 | });
|
1322 | }
|
1323 | if (_darwin) {
|
1324 | let cmd = 'netstat -natv | grep "ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN"';
|
1325 | exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
|
1326 | if (!error) {
|
1327 |
|
1328 | let lines = stdout.toString().split('\n');
|
1329 |
|
1330 | lines.forEach(function (line) {
|
1331 | line = line.replace(/ +/g, ' ').split(' ');
|
1332 | if (line.length >= 8) {
|
1333 | let localip = line[3];
|
1334 | let localport = '';
|
1335 | let localaddress = line[3].split('.');
|
1336 | if (localaddress.length > 1) {
|
1337 | localport = localaddress[localaddress.length - 1];
|
1338 | localaddress.pop();
|
1339 | localip = localaddress.join('.');
|
1340 | }
|
1341 | let peerip = line[4];
|
1342 | let peerport = '';
|
1343 | let peeraddress = line[4].split('.');
|
1344 | if (peeraddress.length > 1) {
|
1345 | peerport = peeraddress[peeraddress.length - 1];
|
1346 | peeraddress.pop();
|
1347 | peerip = peeraddress.join('.');
|
1348 | }
|
1349 | let connstate = line[5];
|
1350 | let pid = parseInt(line[8], 10);
|
1351 | if (connstate) {
|
1352 | result.push({
|
1353 | protocol: line[0],
|
1354 | localaddress: localip,
|
1355 | localport: localport,
|
1356 | peeraddress: peerip,
|
1357 | peerport: peerport,
|
1358 | state: connstate,
|
1359 | pid: pid,
|
1360 | process: ''
|
1361 | });
|
1362 | }
|
1363 | }
|
1364 | });
|
1365 | if (callback) {
|
1366 | callback(result);
|
1367 | }
|
1368 | resolve(result);
|
1369 | }
|
1370 | });
|
1371 | }
|
1372 | if (_windows) {
|
1373 | let cmd = 'netstat -nao';
|
1374 | try {
|
1375 | exec(cmd, util.execOptsWin, function (error, stdout) {
|
1376 | if (!error) {
|
1377 |
|
1378 | let lines = stdout.toString().split('\r\n');
|
1379 |
|
1380 | lines.forEach(function (line) {
|
1381 | line = line.trim().replace(/ +/g, ' ').split(' ');
|
1382 | if (line.length >= 4) {
|
1383 | let localip = line[1];
|
1384 | let localport = '';
|
1385 | let localaddress = line[1].split(':');
|
1386 | if (localaddress.length > 1) {
|
1387 | localport = localaddress[localaddress.length - 1];
|
1388 | localaddress.pop();
|
1389 | localip = localaddress.join(':');
|
1390 | }
|
1391 | let peerip = line[2];
|
1392 | let peerport = '';
|
1393 | let peeraddress = line[2].split(':');
|
1394 | if (peeraddress.length > 1) {
|
1395 | peerport = peeraddress[peeraddress.length - 1];
|
1396 | peeraddress.pop();
|
1397 | peerip = peeraddress.join(':');
|
1398 | }
|
1399 | let pid = line[4];
|
1400 | let connstate = line[3];
|
1401 | if (connstate === 'HERGESTELLT') connstate = 'ESTABLISHED';
|
1402 | if (connstate.startsWith('ABH')) connstate = 'LISTEN';
|
1403 | if (connstate === 'SCHLIESSEN_WARTEN') connstate = 'CLOSE_WAIT';
|
1404 | if (connstate === 'WARTEND') connstate = 'TIME_WAIT';
|
1405 | if (connstate === 'SYN_GESENDET') connstate = 'SYN_SENT';
|
1406 |
|
1407 | if (connstate === 'LISTENING') connstate = 'LISTEN';
|
1408 | if (connstate === 'SYN_RECEIVED') connstate = 'SYN_RECV';
|
1409 | if (connstate === 'FIN_WAIT_1') connstate = 'FIN_WAIT1';
|
1410 | if (connstate === 'FIN_WAIT_2') connstate = 'FIN_WAIT2';
|
1411 | if (connstate) {
|
1412 | result.push({
|
1413 | protocol: line[0].toLowerCase(),
|
1414 | localaddress: localip,
|
1415 | localport: localport,
|
1416 | peeraddress: peerip,
|
1417 | peerport: peerport,
|
1418 | state: connstate,
|
1419 | pid,
|
1420 | process: ''
|
1421 | });
|
1422 | }
|
1423 | }
|
1424 | });
|
1425 | if (callback) {
|
1426 | callback(result);
|
1427 | }
|
1428 | resolve(result);
|
1429 | }
|
1430 | });
|
1431 | } catch (e) {
|
1432 | if (callback) { callback(result); }
|
1433 | resolve(result);
|
1434 | }
|
1435 | }
|
1436 | });
|
1437 | });
|
1438 | }
|
1439 |
|
1440 | exports.networkConnections = networkConnections;
|
1441 |
|
1442 | function networkGatewayDefault(callback) {
|
1443 |
|
1444 | return new Promise((resolve) => {
|
1445 | process.nextTick(() => {
|
1446 | let result = '';
|
1447 | if (_linux || _freebsd || _openbsd || _netbsd) {
|
1448 | let cmd = 'ip route get 1';
|
1449 | try {
|
1450 | exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
|
1451 | if (!error) {
|
1452 | let lines = stdout.toString().split('\n');
|
1453 | const line = lines && lines[0] ? lines[0] : '';
|
1454 | let parts = line.split(' via ');
|
1455 | if (parts && parts[1]) {
|
1456 | parts = parts[1].split(' ');
|
1457 | result = parts[0];
|
1458 | }
|
1459 | if (callback) {
|
1460 | callback(result);
|
1461 | }
|
1462 | resolve(result);
|
1463 | } else {
|
1464 | if (callback) {
|
1465 | callback(result);
|
1466 | }
|
1467 | resolve(result);
|
1468 | }
|
1469 | });
|
1470 | } catch (e) {
|
1471 | if (callback) { callback(result); }
|
1472 | resolve(result);
|
1473 | }
|
1474 | }
|
1475 | if (_darwin) {
|
1476 | let cmd = 'route -n get default';
|
1477 | try {
|
1478 | exec(cmd, { maxBuffer: 1024 * 20000 }, function (error, stdout) {
|
1479 | if (!error) {
|
1480 | let lines = stdout.toString().split('\n').map(line => line.trim());
|
1481 | result = util.getValue(lines, 'gateway');
|
1482 | if (callback) {
|
1483 | callback(result);
|
1484 | }
|
1485 | resolve(result);
|
1486 | } else {
|
1487 | if (callback) {
|
1488 | callback(result);
|
1489 | }
|
1490 | resolve(result);
|
1491 | }
|
1492 | });
|
1493 | } catch (e) {
|
1494 | if (callback) { callback(result); }
|
1495 | resolve(result);
|
1496 | }
|
1497 | }
|
1498 | if (_windows) {
|
1499 | try {
|
1500 | exec('netstat -r', util.execOptsWin, function (error, stdout) {
|
1501 | const lines = stdout.toString().split(os.EOL);
|
1502 | lines.forEach(line => {
|
1503 | line = line.replace(/\s+/g, ' ').trim();
|
1504 | if (line.indexOf('0.0.0.0 0.0.0.0') > -1 && !(/[a-zA-Z]/.test(line))) {
|
1505 | const parts = line.split(' ');
|
1506 | if (parts.length >= 5 && (parts[parts.length - 3]).indexOf('.') > -1) {
|
1507 | result = parts[parts.length - 3];
|
1508 | }
|
1509 | }
|
1510 | });
|
1511 | if (!result) {
|
1512 | util.powerShell('Get-CimInstance -ClassName Win32_IP4RouteTable | Where-Object { $_.Destination -eq \'0.0.0.0\' -and $_.Mask -eq \'0.0.0.0\' }')
|
1513 | .then(data => {
|
1514 | let lines = data.toString().split('\r\n');
|
1515 | if (lines.length > 1 && !result) {
|
1516 | result = util.getValue(lines, 'NextHop');
|
1517 | if (callback) {
|
1518 | callback(result);
|
1519 | }
|
1520 | resolve(result);
|
1521 |
|
1522 |
|
1523 |
|
1524 |
|
1525 |
|
1526 |
|
1527 |
|
1528 |
|
1529 |
|
1530 |
|
1531 |
|
1532 |
|
1533 |
|
1534 |
|
1535 | }
|
1536 | });
|
1537 | } else {
|
1538 | if (callback) {
|
1539 | callback(result);
|
1540 | }
|
1541 | resolve(result);
|
1542 | }
|
1543 | });
|
1544 | } catch (e) {
|
1545 | if (callback) { callback(result); }
|
1546 | resolve(result);
|
1547 | }
|
1548 | }
|
1549 | });
|
1550 | });
|
1551 | }
|
1552 |
|
1553 | exports.networkGatewayDefault = networkGatewayDefault;
|