Skip to content

Commit 5a437c4

Browse files
Tofandeladuh95
authored andcommitted
report: fix network queries in getReport libuv with exclude-network
PR-URL: #55602 Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br>
1 parent e0db9ed commit 5a437c4

File tree

6 files changed

+147
-28
lines changed

6 files changed

+147
-28
lines changed

doc/api/report.md

+48-4
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ is provided below for reference.
3535
```json
3636
{
3737
"header": {
38-
"reportVersion": 3,
38+
"reportVersion": 4,
3939
"event": "exception",
4040
"trigger": "Exception",
4141
"filename": "report.20181221.005011.8974.0.001.json",
@@ -325,6 +325,50 @@ is provided below for reference.
325325
"is_active": true,
326326
"address": "0x000055fc7b2cb180",
327327
"loopIdleTimeSeconds": 22644.8
328+
},
329+
{
330+
"type": "tcp",
331+
"is_active": true,
332+
"is_referenced": true,
333+
"address": "0x000055e70fcb85d8",
334+
"localEndpoint": {
335+
"host": "localhost",
336+
"ip4": "127.0.0.1",
337+
"port": 48986
338+
},
339+
"remoteEndpoint": {
340+
"host": "localhost",
341+
"ip4": "127.0.0.1",
342+
"port": 38573
343+
},
344+
"sendBufferSize": 2626560,
345+
"recvBufferSize": 131072,
346+
"fd": 24,
347+
"writeQueueSize": 0,
348+
"readable": true,
349+
"writable": true
350+
},
351+
{
352+
"type": "tcp",
353+
"is_active": true,
354+
"is_referenced": true,
355+
"address": "0x000055e70fcd68c8",
356+
"localEndpoint": {
357+
"host": "ip6-localhost",
358+
"ip6": "::1",
359+
"port": 52266
360+
},
361+
"remoteEndpoint": {
362+
"host": "ip6-localhost",
363+
"ip6": "::1",
364+
"port": 38573
365+
},
366+
"sendBufferSize": 2626560,
367+
"recvBufferSize": 131072,
368+
"fd": 25,
369+
"writeQueueSize": 0,
370+
"readable": false,
371+
"writable": false
328372
}
329373
],
330374
"workers": [],
@@ -464,9 +508,9 @@ meaning of `SIGUSR2` for the said purposes.
464508
* `--report-signal` Sets or resets the signal for report generation
465509
(not supported on Windows). Default signal is `SIGUSR2`.
466510

467-
* `--report-exclude-network` Exclude `header.networkInterfaces` from the
468-
diagnostic report. By default this is not set and the network interfaces
469-
are included.
511+
* `--report-exclude-network` Exclude `header.networkInterfaces` and disable the reverse DNS queries
512+
in `libuv.*.(remote|local)Endpoint.host` from the diagnostic report.
513+
By default this is not set and the network interfaces are included.
470514

471515
* `--report-exclude-env` Exclude `environmentVariables` from the
472516
diagnostic report. By default this is not set and the environment

src/node_report.cc

+4-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
#include <cwctype>
2424
#include <fstream>
2525

26-
constexpr int NODE_REPORT_VERSION = 3;
26+
constexpr int NODE_REPORT_VERSION = 4;
2727
constexpr int NANOS_PER_SEC = 1000 * 1000 * 1000;
2828
constexpr double SEC_PER_MICROS = 1e-6;
2929
constexpr int MAX_FRAME_COUNT = node::kMaxFrameCountForLogging;
@@ -205,7 +205,9 @@ static void WriteNodeReport(Isolate* isolate,
205205

206206
writer.json_arraystart("libuv");
207207
if (env != nullptr) {
208-
uv_walk(env->event_loop(), WalkHandle, static_cast<void*>(&writer));
208+
uv_walk(env->event_loop(),
209+
exclude_network ? WalkHandleNoNetwork : WalkHandleNetwork,
210+
static_cast<void*>(&writer));
209211

210212
writer.json_start();
211213
writer.json_keyvalue("type", "loop");

src/node_report.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
namespace node {
2020
namespace report {
2121
// Function declarations - utility functions in src/node_report_utils.cc
22-
void WalkHandle(uv_handle_t* h, void* arg);
22+
void WalkHandleNetwork(uv_handle_t* h, void* arg);
23+
void WalkHandleNoNetwork(uv_handle_t* h, void* arg);
2324

2425
template <typename T>
2526
std::string ValueToHexString(T value) {

src/node_report_utils.cc

+35-20
Original file line numberDiff line numberDiff line change
@@ -12,43 +12,51 @@ static constexpr auto null = JSONWriter::Null{};
1212
static void ReportEndpoint(uv_handle_t* h,
1313
struct sockaddr* addr,
1414
const char* name,
15-
JSONWriter* writer) {
15+
JSONWriter* writer,
16+
bool exclude_network) {
1617
if (addr == nullptr) {
1718
writer->json_keyvalue(name, null);
1819
return;
1920
}
2021

2122
uv_getnameinfo_t endpoint;
2223
char* host = nullptr;
23-
char hostbuf[INET6_ADDRSTRLEN];
2424
const int family = addr->sa_family;
2525
const int port = ntohs(family == AF_INET ?
2626
reinterpret_cast<sockaddr_in*>(addr)->sin_port :
2727
reinterpret_cast<sockaddr_in6*>(addr)->sin6_port);
2828

29-
if (uv_getnameinfo(h->loop, &endpoint, nullptr, addr, NI_NUMERICSERV) == 0) {
29+
writer->json_objectstart(name);
30+
if (!exclude_network &&
31+
uv_getnameinfo(h->loop, &endpoint, nullptr, addr, NI_NUMERICSERV) == 0) {
3032
host = endpoint.host;
3133
DCHECK_EQ(port, std::stoi(endpoint.service));
34+
writer->json_keyvalue("host", host);
35+
}
36+
37+
if (family == AF_INET) {
38+
char ipbuf[INET_ADDRSTRLEN];
39+
if (uv_ip4_name(
40+
reinterpret_cast<sockaddr_in*>(addr), ipbuf, sizeof(ipbuf)) == 0) {
41+
writer->json_keyvalue("ip4", ipbuf);
42+
if (host == nullptr) writer->json_keyvalue("host", ipbuf);
43+
}
3244
} else {
33-
const void* src = family == AF_INET ?
34-
static_cast<void*>(
35-
&(reinterpret_cast<sockaddr_in*>(addr)->sin_addr)) :
36-
static_cast<void*>(
37-
&(reinterpret_cast<sockaddr_in6*>(addr)->sin6_addr));
38-
if (uv_inet_ntop(family, src, hostbuf, sizeof(hostbuf)) == 0) {
39-
host = hostbuf;
45+
char ipbuf[INET6_ADDRSTRLEN];
46+
if (uv_ip6_name(
47+
reinterpret_cast<sockaddr_in6*>(addr), ipbuf, sizeof(ipbuf)) == 0) {
48+
writer->json_keyvalue("ip6", ipbuf);
49+
if (host == nullptr) writer->json_keyvalue("host", ipbuf);
4050
}
4151
}
42-
writer->json_objectstart(name);
43-
if (host != nullptr) {
44-
writer->json_keyvalue("host", host);
45-
}
4652
writer->json_keyvalue("port", port);
4753
writer->json_objectend();
4854
}
4955

5056
// Utility function to format libuv socket information.
51-
static void ReportEndpoints(uv_handle_t* h, JSONWriter* writer) {
57+
static void ReportEndpoints(uv_handle_t* h,
58+
JSONWriter* writer,
59+
bool exclude_network) {
5260
struct sockaddr_storage addr_storage;
5361
struct sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage);
5462
uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h);
@@ -65,7 +73,8 @@ static void ReportEndpoints(uv_handle_t* h, JSONWriter* writer) {
6573
default:
6674
break;
6775
}
68-
ReportEndpoint(h, rc == 0 ? addr : nullptr, "localEndpoint", writer);
76+
ReportEndpoint(
77+
h, rc == 0 ? addr : nullptr, "localEndpoint", writer, exclude_network);
6978

7079
switch (h->type) {
7180
case UV_UDP:
@@ -77,7 +86,8 @@ static void ReportEndpoints(uv_handle_t* h, JSONWriter* writer) {
7786
default:
7887
break;
7988
}
80-
ReportEndpoint(h, rc == 0 ? addr : nullptr, "remoteEndpoint", writer);
89+
ReportEndpoint(
90+
h, rc == 0 ? addr : nullptr, "remoteEndpoint", writer, exclude_network);
8191
}
8292

8393
// Utility function to format libuv pipe information.
@@ -155,7 +165,7 @@ static void ReportPath(uv_handle_t* h, JSONWriter* writer) {
155165
}
156166

157167
// Utility function to walk libuv handles.
158-
void WalkHandle(uv_handle_t* h, void* arg) {
168+
void WalkHandle(uv_handle_t* h, void* arg, bool exclude_network = false) {
159169
const char* type = uv_handle_type_name(h->type);
160170
JSONWriter* writer = static_cast<JSONWriter*>(arg);
161171
uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h);
@@ -177,7 +187,7 @@ void WalkHandle(uv_handle_t* h, void* arg) {
177187
break;
178188
case UV_TCP:
179189
case UV_UDP:
180-
ReportEndpoints(h, writer);
190+
ReportEndpoints(h, writer, exclude_network);
181191
break;
182192
case UV_NAMED_PIPE:
183193
ReportPipeEndpoints(h, writer);
@@ -267,6 +277,11 @@ void WalkHandle(uv_handle_t* h, void* arg) {
267277
}
268278
writer->json_end();
269279
}
270-
280+
void WalkHandleNetwork(uv_handle_t* h, void* arg) {
281+
WalkHandle(h, arg, false);
282+
}
283+
void WalkHandleNoNetwork(uv_handle_t* h, void* arg) {
284+
WalkHandle(h, arg, true);
285+
}
271286
} // namespace report
272287
} // namespace node

test/common/report.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ function _validateContent(report, fields = []) {
110110
'glibcVersionRuntime', 'glibcVersionCompiler', 'cwd',
111111
'reportVersion', 'networkInterfaces', 'threadId'];
112112
checkForUnknownFields(header, headerFields);
113-
assert.strictEqual(header.reportVersion, 3); // Increment as needed.
113+
assert.strictEqual(header.reportVersion, 4); // Increment as needed.
114114
assert.strictEqual(typeof header.event, 'string');
115115
assert.strictEqual(typeof header.trigger, 'string');
116116
assert(typeof header.filename === 'string' || header.filename === null);

test/report/test-report-exclude-network.js

+57
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22
require('../common');
3+
const http = require('node:http');
34
const assert = require('node:assert');
45
const { spawnSync } = require('node:child_process');
56
const tmpdir = require('../common/tmpdir');
@@ -38,4 +39,60 @@ describe('report exclude network option', () => {
3839
const report = process.report.getReport();
3940
assert.strictEqual(report.header.networkInterfaces, undefined);
4041
});
42+
43+
it('should not do DNS queries in libuv if exclude network', async () => {
44+
const server = http.createServer(function(req, res) {
45+
res.writeHead(200, { 'Content-Type': 'text/plain' });
46+
res.end();
47+
});
48+
let ipv6Available = true;
49+
const port = await new Promise((resolve) => server.listen(0, async () => {
50+
await Promise.all([
51+
fetch('http://127.0.0.1:' + server.address().port),
52+
fetch('http://[::1]:' + server.address().port).catch(() => ipv6Available = false),
53+
]);
54+
resolve(server.address().port);
55+
server.close();
56+
}));
57+
process.report.excludeNetwork = false;
58+
let report = process.report.getReport();
59+
let tcp = report.libuv.filter((uv) => uv.type === 'tcp' && uv.remoteEndpoint?.port === port);
60+
assert.strictEqual(tcp.length, ipv6Available ? 2 : 1);
61+
const findHandle = (local, ip4 = true) => {
62+
return tcp.find(
63+
({ [local ? 'localEndpoint' : 'remoteEndpoint']: ep }) =>
64+
(ep[ip4 ? 'ip4' : 'ip6'] === (ip4 ? '127.0.0.1' : '::1')),
65+
)?.[local ? 'localEndpoint' : 'remoteEndpoint'];
66+
};
67+
try {
68+
// The reverse DNS of 127.0.0.1 can be a lot of things other than localhost
69+
// it could resolve to the server name for instance
70+
assert.notStrictEqual(findHandle(true)?.host, '127.0.0.1');
71+
assert.notStrictEqual(findHandle(false)?.host, '127.0.0.1');
72+
73+
if (ipv6Available) {
74+
assert.notStrictEqual(findHandle(true, false)?.host, '::1');
75+
assert.notStrictEqual(findHandle(false, false)?.host, '::1');
76+
}
77+
} catch (e) {
78+
throw new Error(e?.message + ' in ' + JSON.stringify(tcp, null, 2), { cause: e });
79+
}
80+
81+
process.report.excludeNetwork = true;
82+
report = process.report.getReport();
83+
tcp = report.libuv.filter((uv) => uv.type === 'tcp' && uv.remoteEndpoint?.port === port);
84+
85+
try {
86+
assert.strictEqual(tcp.length, ipv6Available ? 2 : 1);
87+
assert.strictEqual(findHandle(true)?.host, '127.0.0.1');
88+
assert.strictEqual(findHandle(false)?.host, '127.0.0.1');
89+
90+
if (ipv6Available) {
91+
assert.strictEqual(findHandle(true, false)?.host, '::1');
92+
assert.strictEqual(findHandle(false, false)?.host, '::1');
93+
}
94+
} catch (e) {
95+
throw new Error(e?.message + ' in ' + JSON.stringify(tcp, null, 2), { cause: e });
96+
}
97+
});
4198
});

0 commit comments

Comments
 (0)