systeminformation/lib/network.js
2017-04-23 14:36:41 +02:00

412 lines
14 KiB
JavaScript

'use strict';
// ==================================================================================
// network.js
// ----------------------------------------------------------------------------------
// Description: System Information - library
// for Node.js
// Copyright: (c) 2014 - 2017
// Author: Sebastian Hildebrandt
// ----------------------------------------------------------------------------------
// License: MIT
// ==================================================================================
// 9. Network
// ----------------------------------------------------------------------------------
const os = require('os');
const exec = require('child_process').exec;
const execSync = require('child_process').execSync;
const fs = require('fs');
const util = require('./util');
let _platform = os.type();
const _linux = (_platform === 'Linux');
const _darwin = (_platform === 'Darwin');
const _windows = (_platform === 'Windows_NT');
const NOT_SUPPORTED = 'not supported';
let _network = {};
let _default_iface;
function getDefaultNetworkInterface() {
if (!_default_iface) {
let ifacename = '';
let cmd = (_linux ? "route 2>/dev/null | grep default | awk '{print $8}'" : "route get 0.0.0.0 2>/dev/null | grep interface: | awk '{print $2}'");
let result = execSync(cmd);
ifacename = result.toString().split('\n')[0];
if (!ifacename) { // fallback - "first" external interface
const sortObject = o => Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {});
let ifaces = sortObject(os.networkInterfaces());
for (let dev in ifaces) {
if (ifaces.hasOwnProperty(dev)) {
ifaces[dev].forEach(function (details) {
if (details && details.internal === false) {
ifacename = ifacename || dev;
}
})
}
}
}
if (ifacename) _default_iface = ifacename;
}
return _default_iface;
}
exports.getDefaultNetworkInterface = getDefaultNetworkInterface;
function networkInterfaceDefault(callback) {
return new Promise((resolve, reject) => {
process.nextTick(() => {
if (_windows) {
let error = new Error(NOT_SUPPORTED);
if (callback) { callback(NOT_SUPPORTED) }
reject(error);
}
let result = getDefaultNetworkInterface();
if (callback) { callback(result) }
resolve(result);
});
});
}
exports.networkInterfaceDefault = networkInterfaceDefault;
// --------------------------
// NET - interfaces
function networkInterfaces(callback) {
return new Promise((resolve) => {
process.nextTick(() => {
let ifaces = os.networkInterfaces();
let result = [];
for (let dev in ifaces) {
let ip4 = '';
let ip6 = '';
let mac = '';
if (ifaces.hasOwnProperty(dev)) {
ifaces[dev].forEach(function (details) {
if (details.family === 'IPv4') {
ip4 = details.address
}
if (details.family === 'IPv6') {
ip6 = details.address
}
mac = details.mac
});
let internal = (ifaces[dev] && ifaces[dev][0]) ? ifaces[dev][0].internal : null;
result.push({ iface: dev, ip4: ip4, ip6: ip6, mac: mac, internal: internal })
}
}
if (callback) { callback(result) }
resolve(result);
});
});
}
exports.networkInterfaces = networkInterfaces;
// --------------------------
// NET - Speed
function calcNetworkSpeed(iface, rx, tx, operstate) {
let result = {
iface: iface,
operstate: operstate,
rx: 0,
tx: 0,
rx_sec: -1,
tx_sec: -1,
ms: 0
};
if (_network[iface] && _network[iface].ms) {
result.rx = rx;
result.tx = tx;
result.ms = Date.now() - _network[iface].ms;
result.rx_sec = (rx - _network[iface].rx) / (result.ms / 1000);
result.tx_sec = (tx - _network[iface].tx) / (result.ms / 1000);
_network[iface].rx = rx;
_network[iface].tx = tx;
_network[iface].rx_sec = result.rx_sec;
_network[iface].tx_sec = result.tx_sec;
_network[iface].ms = Date.now();
_network[iface].last_ms = result.ms;
} else {
result.rx = rx;
result.tx = tx;
if (!_network[iface]) _network[iface] = {};
_network[iface].rx = rx;
_network[iface].tx = tx;
_network[iface].rx_sec = -1;
_network[iface].tx_sec = -1;
_network[iface].ms = Date.now();
_network[iface].last_ms = 0;
}
return result;
}
function networkStats(iface, callback) {
// fallback - if only callback is given
if (util.isFunction(iface) && !callback) {
callback = iface;
iface = '';
}
return new Promise((resolve, reject) => {
process.nextTick(() => {
if (_windows) {
let error = new Error(NOT_SUPPORTED);
if (callback) { callback(NOT_SUPPORTED) }
reject(error);
}
_default_iface = _default_iface || getDefaultNetworkInterface();
iface = iface || _default_iface; // (_darwin ? 'en0' : 'eth0');
let result = {
iface: iface,
operstate: 'unknown',
rx: 0,
tx: 0,
rx_sec: -1,
tx_sec: -1,
ms: 0
};
let operstate = 'unknown';
let rx = 0;
let tx = 0;
let cmd, lines, stats;
if (!_network[iface] || (_network[iface] && !_network[iface].ms) || (_network[iface] && _network[iface].ms && Date.now() - _network[iface].ms >= 500)) {
if (_linux) {
if (fs.existsSync('/sys/class/net/' + iface)) {
cmd =
"cat /sys/class/net/" + iface + "/operstate; " +
"cat /sys/class/net/" + iface + "/statistics/rx_bytes; " +
"cat /sys/class/net/" + iface + "/statistics/tx_bytes; ";
exec(cmd, function (error, stdout) {
if (!error) {
lines = stdout.toString().split('\n');
operstate = lines[0].trim();
rx = parseInt(lines[1]);
tx = parseInt(lines[2]);
result = calcNetworkSpeed(iface, rx, tx, operstate);
}
if (callback) { callback(result) }
resolve(result);
});
} else {
if (callback) { callback(result) }
resolve(result);
}
}
if (_darwin) {
cmd = "ifconfig " + iface + " | grep 'status'";
exec(cmd, function (error, stdout) {
result.operstate = (stdout.toString().split(':')[1] || '').trim();
result.operstate = (result.operstate || '').toLowerCase();
result.operstate = (result.operstate === 'active' ? 'up' : (result.operstate === 'inactive' ? 'down' : 'unknown'));
cmd = "netstat -bI " + iface;
exec(cmd, function (error, stdout) {
if (!error) {
lines = stdout.toString().split('\n');
// if there is less than 2 lines, no information for this interface was found
if (lines.length > 1 && lines[1].trim() !== '') {
// skip header line
// use the second line because it is tied to the NIC instead of the ipv4 or ipv6 address
stats = lines[1].replace(/ +/g, " ").split(' ');
rx = parseInt(stats[6]);
tx = parseInt(stats[9]);
result = calcNetworkSpeed(iface, rx, tx, operstate);
}
}
if (callback) { callback(result) }
resolve(result);
});
});
}
} else {
result.rx = _network[iface].rx;
result.tx = _network[iface].tx;
result.rx_sec = _network[iface].rx_sec;
result.tx_sec = _network[iface].tx_sec;
result.ms = _network[iface].last_ms;
if (callback) { callback(result) }
resolve(result);
}
});
});
}
exports.networkStats = networkStats;
// --------------------------
// NET - connections (sockets)
function networkConnections(callback) {
return new Promise((resolve, reject) => {
process.nextTick(() => {
if (_windows) {
let error = new Error(NOT_SUPPORTED);
if (callback) { callback(NOT_SUPPORTED) }
reject(error);
}
let result = [];
if (_linux) {
let cmd = "netstat -tuna | grep 'ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN\\|VERBUNDEN'";
exec(cmd, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
lines.forEach(function (line) {
line = line.replace(/ +/g, " ").split(' ');
if (line.length >= 6) {
let localip = line[3];
let localport = '';
let localaddress = line[3].split(':');
if (localaddress.length > 1) {
localport = localaddress[localaddress.length - 1];
localaddress.pop();
localip = localaddress.join(':');
}
let peerip = line[4];
let peerport = '';
let peeraddress = line[4].split(':');
if (peeraddress.length > 1) {
peerport = peeraddress[peeraddress.length - 1];
peeraddress.pop();
peerip = peeraddress.join(':');
}
let connstate = line[5];
if (connstate === 'VERBUNDEN') connstate = 'ESTABLISHED';
if (connstate) {
result.push({
protocol: line[0],
localaddress: localip,
localport: localport,
peeraddress: peerip,
peerport: peerport,
state: connstate
})
}
}
});
if (callback) {
callback(result)
}
resolve(result);
} else {
cmd = "ss -tuna | grep 'ESTAB\\|SYN-SENT\\|SYN-RECV\\|FIN-WAIT1\\|FIN-WAIT2\\|TIME-WAIT\\|CLOSE\\|CLOSE-WAIT\\|LAST-ACK\\|LISTEN\\|CLOSING'";
exec(cmd, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
lines.forEach(function (line) {
line = line.replace(/ +/g, " ").split(' ');
if (line.length >= 6) {
let localip = line[4];
let localport = '';
let localaddress = line[4].split(':');
if (localaddress.length > 1) {
localport = localaddress[localaddress.length - 1];
localaddress.pop();
localip = localaddress.join(':');
}
let peerip = line[5];
let peerport = '';
let peeraddress = line[5].split(':');
if (peeraddress.length > 1) {
peerport = peeraddress[peeraddress.length - 1];
peeraddress.pop();
peerip = peeraddress.join(':');
}
let connstate = line[1];
if (connstate === 'ESTAB') connstate = 'ESTABLISHED';
if (connstate === 'TIME-WAIT') connstate = 'TIME_WAIT';
if (connstate) {
result.push({
protocol: line[0],
localaddress: localip,
localport: localport,
peeraddress: peerip,
peerport: peerport,
state: connstate
})
}
}
});
}
if (callback) {
callback(result)
}
resolve(result);
})
}
})
}
if (_darwin) {
let cmd = "netstat -nat | grep 'ESTABLISHED\\|SYN_SENT\\|SYN_RECV\\|FIN_WAIT1\\|FIN_WAIT2\\|TIME_WAIT\\|CLOSE\\|CLOSE_WAIT\\|LAST_ACK\\|LISTEN\\|CLOSING\\|UNKNOWN'";
exec(cmd, function (error, stdout) {
if (!error) {
let lines = stdout.toString().split('\n');
lines.forEach(function (line) {
line = line.replace(/ +/g, " ").split(' ');
if (line.length >= 6) {
let localip = line[3];
let localport = '';
let localaddress = line[3].split('.');
if (localaddress.length > 1) {
localport = localaddress[localaddress.length - 1];
localaddress.pop();
localip = localaddress.join('.');
}
let peerip = line[4];
let peerport = '';
let peeraddress = line[4].split('.');
if (peeraddress.length > 1) {
peerport = peeraddress[peeraddress.length - 1];
peeraddress.pop();
peerip = peeraddress.join('.');
}
let connstate = line[5];
if (connstate) {
result.push({
protocol: line[0],
localaddress: localip,
localport: localport,
peeraddress: peerip,
peerport: peerport,
state: connstate
})
}
}
});
if (callback) {
callback(result)
}
resolve(result);
}
})
}
});
});
}
exports.networkConnections = networkConnections;