UNPKG

neoss

Version:

<div align="center"> <h1>neoss</h1> <i>Socket statistics, with a UI.</i> </div> <p align="center"> <a href="https://img.shields.io/github/v/release/pablolec/neoss" target="_blank"> <img src="https://img.shields.io/github/v/release/pablolec/neo

230 lines (201 loc) 5.77 kB
import { readFileSync } from "fs"; let sockets = {}; /** * Drive async workflow for socket file descriptors acquisition. * * @returns - Sockets map {inode:statistics,} */ export async function getSockets(): Promise<{}> { let promises: Promise<void>[] = []; promises.push(readProcFile("tcp")); promises.push(readProcFile("udp")); promises.push(readProcFile("tcp6")); promises.push(readProcFile("udp6")); await Promise.all(promises); return sockets; } /** * Parse file content data for relevant socket statistics. * * @param data - Raw file text content * @param type - Transport protocol and version number */ function parseSockets(data: string, type: string) { let lines = data.split(/\r\n|\r|\n/); lines.shift(); for (let line of lines) { if (!line) { continue; } let elements = line.trim().split(/\s+/); let inode = elements[9]; sockets[inode] = {}; sockets[inode].protocol = type.slice(0, 3); sockets[inode].state = formatState(elements[3]); [sockets[inode].receiveQueue, sockets[inode].sendQueue] = formatRxTx(elements[4]); if (type.includes("6")) { [sockets[inode].localAddress, sockets[inode].localPort] = formatIPv6(elements[1]); [sockets[inode].peerAddress, sockets[inode].peerPort] = formatIPv6(elements[2]); } else { [sockets[inode].localAddress, sockets[inode].localPort] = formatIPv4(elements[1]); [sockets[inode].peerAddress, sockets[inode].peerPort] = formatIPv4(elements[2]); } let isAddressNull = sockets[inode].localAddress == null || sockets[inode].peerAddress == null let isAddressLocalhost = sockets[inode].localAddress == sockets[inode].peerAddress || sockets[inode].peerAddress == "localhost" if (isAddressNull || isAddressLocalhost) { delete sockets[inode]; continue; } sockets[inode].users = {}; sockets[inode].inode = inode; } } /** * Format unix hex representation of IPv4 to its regular expression. * * @param line - Raw hex representation * @returns - Formated address */ function formatIPv4(line: string): (string | null)[] { let lineMap = line.split(":"); let hexAddress = lineMap[0]; let hexPort = lineMap[1]; let hexArray = hexAddress .split(/(..)/g) .filter((s: any) => s) .map(hexToDecimal); hexArray.reverse(); let address: string | null; if (parseInt(hexArray.join("")) == 0) { // Catch undefined addresses address = null; } else { address = hexArray.join("."); } let port = hexToDecimal(hexPort) + ""; return [address, port]; } /** * Format unix hex representation of IPv6 to its regular expression. * * @param line - Raw hex representation * @returns - Formated address */ function formatIPv6(line: string): (string | null)[] { let lineMap = line.split(":"); let hexAddress = lineMap[0]; let hexPort = lineMap[1]; let hexArray = hexAddress.split(/(....)/g).filter((s: string) => s); hexArray.forEach(function (hex: string, i: number) { let splitHex = hex.split(/(..)/g).filter((s: any) => s); splitHex.reverse(); hexArray[i] = splitHex.join(""); }); for (let i = 0; i < hexArray.length; i += 2) { [hexArray[i], hexArray[i + 1]] = [hexArray[i + 1], hexArray[i]]; } let address: string | null; let sum = hexToDecimal(hexArray.join("")); if (sum == 0) { // Catch undefined addresses address = null; } else if (sum == 1) { // Shorten loopback address address = "::1"; } else if (hexArray.slice(0, 6).join("") == "00000000000000000000FFFF") { // Catch IPv4 expressed in IPv6 notation let ipV4Part = hexArray[6] + hexArray[7]; address = ipV4Part .split(/(..)/g) .filter((s: any) => s) .map(hexToDecimal) .join("."); } else { hexArray.forEach(function (hex: string, i: number) { // Notation shortening let hexInt = parseInt(hex, 16) + ""; hexArray[i] = hexInt == "0000" ? "" : hexArray[i]; }); address = hexArray.join(":"); } let port = hexToDecimal(hexPort) + ""; return [address, port]; } /** * Format receiveQueue and sendQueue hex representation to decimal. * * @param line - Raw hex representation * @returns - Decimal values */ function formatRxTx(line: string): string[] { let lineMap = line.split(":"); let rx = hexToDecimal(lineMap[0]) + ""; let tx = hexToDecimal(lineMap[1]) + ""; return [rx, tx]; } /** * Get a definition for socket state from hex value * * @param hex - Raw hex value * @returns - State definition */ function formatState(hex: string): string { let state = ""; switch (hex) { case "01": state = "ESTAB"; break; case "02": state = "SYN_SENT"; break; case "03": state = "SYN_RECV"; break; case "04": state = "FIN_WAIT1"; break; case "05": state = "FIN_WAIT2"; break; case "06": state = "TIME_WAIT"; break; case "07": state = "CLOSED"; break; case "08": state = "CLOSE_WAIT"; break; case "09": state = "LAST_ACK"; break; case "0A": state = "LISTEN"; break; case "0B": state = "CLOSING"; break; case "0C": state = "NEW_SYN_RECV"; break; } return state; } /** * Read process file content and initiate its parsing. * * @param file - File name (process inode) */ async function readProcFile(file: string) { let content = readFileSync("/proc/net/" + file, "utf8"); parseSockets(content, file); } /** * Convert a hex string representation to its decimal value. * * @param str - Hex string representation * @returns - Decimal value */ function hexToDecimal(str: string): number { return parseInt(Number("0x" + str) + "", 10); }