From 4b91e4dafdad472da4550aaab3c21727710a647d Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 23 Jul 2019 19:13:30 -0400 Subject: [PATCH] report: include network interfaces in report PR-URL: https://github.com/nodejs/node/pull/28911 Reviewed-By: Richard Lau Reviewed-By: Anna Henningsen Reviewed-By: Trivikram Kamat Reviewed-By: Yongsheng Zhang Reviewed-By: James M Snell Reviewed-By: Rich Trott --- doc/api/report.md | 10 ++++++++ src/node_report.cc | 53 +++++++++++++++++++++++++++++++++++++++++++ test/common/report.js | 25 +++++++++++++++++++- 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/doc/api/report.md b/doc/api/report.md index 6f9adb1f14c406..8819d2802b4373 100644 --- a/doc/api/report.md +++ b/doc/api/report.md @@ -83,6 +83,16 @@ is provided below for reference. "irq": 0 } ], + "networkInterfaces": [ + { + "name": "en0", + "internal": false, + "mac": "13:10:de:ad:be:ef", + "address": "10.0.0.37", + "netmask": "255.255.255.0", + "family": "IPv4" + } + ], "host": "test_machine" }, "javascriptStack": { diff --git a/src/node_report.cc b/src/node_report.cc index 4f2f1dd1abebfe..8f480e658f7b7b 100644 --- a/src/node_report.cc +++ b/src/node_report.cc @@ -67,6 +67,7 @@ static void PrintLoadedLibraries(JSONWriter* writer); static void PrintComponentVersions(JSONWriter* writer); static void PrintRelease(JSONWriter* writer); static void PrintCpuInfo(JSONWriter* writer); +static void PrintNetworkInterfaceInfo(JSONWriter* writer); // External function to trigger a report, writing to file. // The 'name' parameter is in/out: an input filename is used @@ -318,6 +319,7 @@ static void PrintVersionInformation(JSONWriter* writer) { } PrintCpuInfo(writer); + PrintNetworkInterfaceInfo(writer); char host[UV_MAXHOSTNAMESIZE]; size_t host_size = sizeof(host); @@ -348,6 +350,57 @@ static void PrintCpuInfo(JSONWriter* writer) { } } +static void PrintNetworkInterfaceInfo(JSONWriter* writer) { + uv_interface_address_t* interfaces; + char ip[INET6_ADDRSTRLEN]; + char netmask[INET6_ADDRSTRLEN]; + char mac[18]; + int count; + + if (uv_interface_addresses(&interfaces, &count) == 0) { + writer->json_arraystart("networkInterfaces"); + + for (int i = 0; i < count; i++) { + writer->json_start(); + writer->json_keyvalue("name", interfaces[i].name); + writer->json_keyvalue("internal", !!interfaces[i].is_internal); + snprintf(mac, + sizeof(mac), + "%02x:%02x:%02x:%02x:%02x:%02x", + static_cast(interfaces[i].phys_addr[0]), + static_cast(interfaces[i].phys_addr[1]), + static_cast(interfaces[i].phys_addr[2]), + static_cast(interfaces[i].phys_addr[3]), + static_cast(interfaces[i].phys_addr[4]), + static_cast(interfaces[i].phys_addr[5])); + writer->json_keyvalue("mac", mac); + + if (interfaces[i].address.address4.sin_family == AF_INET) { + uv_ip4_name(&interfaces[i].address.address4, ip, sizeof(ip)); + uv_ip4_name(&interfaces[i].netmask.netmask4, netmask, sizeof(netmask)); + writer->json_keyvalue("address", ip); + writer->json_keyvalue("netmask", netmask); + writer->json_keyvalue("family", "IPv4"); + } else if (interfaces[i].address.address4.sin_family == AF_INET6) { + uv_ip6_name(&interfaces[i].address.address6, ip, sizeof(ip)); + uv_ip6_name(&interfaces[i].netmask.netmask6, netmask, sizeof(netmask)); + writer->json_keyvalue("address", ip); + writer->json_keyvalue("netmask", netmask); + writer->json_keyvalue("family", "IPv6"); + writer->json_keyvalue("scopeid", + interfaces[i].address.address6.sin6_scope_id); + } else { + writer->json_keyvalue("family", "unknown"); + } + + writer->json_end(); + } + + writer->json_arrayend(); + uv_free_interface_addresses(interfaces, count); + } +} + // Report the JavaScript stack. static void PrintJavaScriptStack(JSONWriter* writer, Isolate* isolate, diff --git a/test/common/report.js b/test/common/report.js index be1da58ff99a3c..fdb15924cab770 100644 --- a/test/common/report.js +++ b/test/common/report.js @@ -2,6 +2,7 @@ 'use strict'; const assert = require('assert'); const fs = require('fs'); +const net = require('net'); const os = require('os'); const path = require('path'); const util = require('util'); @@ -73,7 +74,7 @@ function _validateContent(report) { 'componentVersions', 'release', 'osName', 'osRelease', 'osVersion', 'osMachine', 'cpus', 'host', 'glibcVersionRuntime', 'glibcVersionCompiler', 'cwd', - 'reportVersion']; + 'reportVersion', 'networkInterfaces']; checkForUnknownFields(header, headerFields); assert.strictEqual(header.reportVersion, 1); // Increment as needed. assert.strictEqual(typeof header.event, 'string'); @@ -112,6 +113,28 @@ function _validateContent(report) { return c.model === cpu.model; })); }); + + assert(Array.isArray(header.networkInterfaces)); + header.networkInterfaces.forEach((iface) => { + assert.strictEqual(typeof iface.name, 'string'); + assert.strictEqual(typeof iface.internal, 'boolean'); + assert(/^([0-9A-F][0-9A-F]:){5}[0-9A-F]{2}$/i.test(iface.mac)); + + if (iface.family === 'IPv4') { + assert.strictEqual(net.isIPv4(iface.address), true); + assert.strictEqual(net.isIPv4(iface.netmask), true); + assert.strictEqual(iface.scopeid, undefined); + } else if (iface.family === 'IPv6') { + assert.strictEqual(net.isIPv6(iface.address), true); + assert.strictEqual(net.isIPv6(iface.netmask), true); + assert(Number.isInteger(iface.scopeid)); + } else { + assert.strictEqual(iface.family, 'unknown'); + assert.strictEqual(iface.address, undefined); + assert.strictEqual(iface.netmask, undefined); + assert.strictEqual(iface.scopeid, undefined); + } + }); assert.strictEqual(header.host, os.hostname()); // Verify the format of the javascriptStack section.