mirror of
https://github.com/Cacti/cacti.git
synced 2026-10-28 07:37:11 +09:00
* fix: detect a failed SNMP walk by exit code, not by device data cacti_snmp_walk() discarded the entire walk when its output contained the word Timeout. That output is the walk itself, one line per OID, so a device with an ifAlias of 'Timeout Monitor' or a matching sysDescr emptied the result and data_query.php then dropped every index for the device. The check could not detect a real timeout either. net-snmp writes that to stderr and neither walk command redirects it, so the matched string was always device data. cacti_snmp_get() already reads the exit code for exactly this reason; exec_into_array() exposes it by reference. Also refuse a walk with empty credentials, matching cacti_snmp_get, get_raw and getnext. An unknown v3 protocol previously built a credential-less snmpwalk and failed with no log line. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: cover the credential guard and refresh the security baselines Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: give the exec_into_array stub the real signature The stub dropped the by-reference exit code that lib/functions.php exposes, so any code reading it saw 0 regardless of what the command returned. That is why the walk's failure detection could regress to matching stdout without a test noticing. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: expect the exit-code wording for a failed walk Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
47 lines
1.9 KiB
PHP
47 lines
1.9 KiB
PHP
<?php
|
|
/*
|
|
+-------------------------------------------------------------------------+
|
|
| Copyright (C) 2004-2026 The Cacti Group |
|
|
+-------------------------------------------------------------------------+
|
|
| Cacti: The Complete RRDtool-based Graphing Solution |
|
|
+-------------------------------------------------------------------------+
|
|
*/
|
|
|
|
$snmpSource = file_get_contents(dirname(__DIR__, 3) . '/lib/snmp.php');
|
|
|
|
function cacti_snmp_walk_body(string $source) : string {
|
|
$start = strpos($source, 'function cacti_snmp_walk(');
|
|
$end = strpos($source, "\nfunction ", $start + 1);
|
|
|
|
return substr($source, $start, $end - $start);
|
|
}
|
|
|
|
test('a failed walk is detected by the exit code, not by scanning device data', function () use ($snmpSource) {
|
|
$body = cacti_snmp_walk_body($snmpSource);
|
|
|
|
// net-snmp writes a timeout to stderr, which exec() does not capture, so
|
|
// matching 'Timeout' against walk output only ever matched device values
|
|
// such as an ifAlias of 'Timeout Monitor' and discarded the whole walk.
|
|
expect($body)->not->toContain("str_contains(implode(' ', \$temp_array), 'Timeout')")
|
|
->and($body)->toContain('$return_code != 0')
|
|
->and($body)->toContain('exec_into_array($command, $return_code)');
|
|
});
|
|
|
|
test('the walk refuses to run without credentials, as its siblings do', function () use ($snmpSource) {
|
|
expect(cacti_snmp_walk_body($snmpSource))->toContain('empty($snmp_auth)');
|
|
});
|
|
|
|
test('device values containing Timeout survive a healthy walk', function () {
|
|
// The guard the fix removes, applied to a healthy walk.
|
|
$rows = [
|
|
'.1.3.6.1.2.1.31.1.1.1.18.1 = STRING: Uplink to core',
|
|
'.1.3.6.1.2.1.31.1.1.1.18.2 = STRING: Timeout Monitor probe',
|
|
];
|
|
|
|
$discardedByOldGuard = str_contains(implode(' ', $rows), 'Timeout');
|
|
$discardedByExitCode = (0 != 0);
|
|
|
|
expect($discardedByOldGuard)->toBeTrue()
|
|
->and($discardedByExitCode)->toBeFalse();
|
|
});
|