fix(discovery): recover an nmap scan that succeeded despite a benign stderr warning

node-nmap (the vendored library, not our code) treats ANY stderr
output from the nmap binary as a fatal scan error -- including nmap's
own harmless RTT-calibration warning ("RTTVAR has grown to over N
seconds, decreasing to M"), which it prints *during* a scan that goes
on to complete normally. That meant a real, successful scan (valid XML
already sitting in the library's rawData) got discarded and reported
as a failed run with zero hosts discovered -- not just log noise as
initially assumed.

Recover in our own plugin code by detecting this specific known-benign
message and manually re-running node-nmap's own XML-parse-then-complete
path when there's actually output to parse. A genuine parse failure or
any other error message still rejects exactly as before -- this only
widens the recovery path.
This commit is contained in:
2026-08-10 22:14:13 -04:00
parent b6a82d58d5
commit e313697bfd
3 changed files with 70 additions and 3 deletions
+21 -2
View File
@@ -88,9 +88,28 @@ module.exports = {
var msg = (error && error.message) || String(error);
if (/nmap.*not found|command location/i.test(msg)) {
reject(new Error('nmap binary not installed in the container image (rebuild with Dockerfile.openldap, which apk-adds nmap)'));
} else {
reject(error);
return;
}
// node-nmap (node_modules/node-nmap/index.js) treats ANY stderr
// output from the nmap binary as a fatal scan error -- including
// nmap's own benign RTT timing-calibration warnings ("RTTVAR has
// grown to over N seconds, decreasing to M"), which it prints
// *during* a scan that goes on to complete normally. That means a
// scan that actually succeeded (valid XML already sitting in
// scan.rawData) got thrown away and reported as a failed run with
// zero hosts discovered -- not just a noisy log line. Recover by
// manually re-running node-nmap's own XML-parse-then-complete path
// (rawDataHandler -> scanComplete -> the 'complete' listener above)
// when the "error" is this specific known-benign nmap message and
// there's actually output to parse. A genuine XML parse failure
// re-emits 'error' with a different message, which falls through to
// reject() below same as before -- this only widens the recovery
// path, it doesn't swallow real failures.
if (/RTTVAR has grown/i.test(msg) && scan.rawData) {
scan.rawDataHandler(scan.rawData);
return;
}
reject(error);
});
scan.startScan();