mactrack_resolver.php dereferences the first PTR answer without checking that one came back:
$resp = $resolver->query($dns_hostname, 'PTR');
$dns_hostname = $resp->answer[0]->ptrdname;
An address with no PTR record answers NOERROR with an empty answer section. That is not an exception, so the catch (Net_DNS2_Exception $e) below never runs. Verified against a live resolver with the bundled Net_DNS2 1.5.5:
1.1.1.1 (has a PTR) rcode=0 answer_count=1 answer[0] set
cloudflare.com (NODATA, no PTR) rcode=0 answer_count=0 answer[0] UNSET
so the second case yields Undefined array key 0, Attempt to read property "ptrdname" on null, and $dns_hostname = NULL.
The row is then written with an empty dns_hostname, and the selection query eleven lines above is:
SELECT * FROM mac_track_temp_ports
WHERE ip_address != ''
AND (dns_hostname = '' OR dns_hostname IS NULL)
so the same address is queried again on the next pass, and every pass after that. Addresses without reverse DNS are the common case on internal ranges, so this is a permanent retry loop plus two PHP warnings per address per pass.
Newly reachable. Before #342 the branches were inverted:
if (cacti_sizeof($nameservers)) {
$use_resolver = false; // resolver built only when NO nameservers were set
$resolver = false;
} else {
Anyone with mt_dns_primary configured silently fell through to gethostbyaddr() and never entered this path. #342 corrected the inversion, which is right, and in doing so activated the bug for the first time.
Second defect in the same block. The catch branch assigns gethostbyaddr() straight to $dns_hostname and, unlike the else branch twelve lines down, does not fall back to the IP address when that returns false. Those rows are also re-selected forever.
Fix: treat a missing answer as an empty result and fall through to gethostbyaddr(), then store the address itself when nothing resolves, matching what the no-resolver branch already does.
mactrack_resolver.phpdereferences the first PTR answer without checking that one came back:An address with no PTR record answers NOERROR with an empty answer section. That is not an exception, so the
catch (Net_DNS2_Exception $e)below never runs. Verified against a live resolver with the bundled Net_DNS2 1.5.5:so the second case yields
Undefined array key 0,Attempt to read property "ptrdname" on null, and$dns_hostname = NULL.The row is then written with an empty
dns_hostname, and the selection query eleven lines above is:so the same address is queried again on the next pass, and every pass after that. Addresses without reverse DNS are the common case on internal ranges, so this is a permanent retry loop plus two PHP warnings per address per pass.
Newly reachable. Before #342 the branches were inverted:
Anyone with
mt_dns_primaryconfigured silently fell through togethostbyaddr()and never entered this path. #342 corrected the inversion, which is right, and in doing so activated the bug for the first time.Second defect in the same block. The
catchbranch assignsgethostbyaddr()straight to$dns_hostnameand, unlike theelsebranch twelve lines down, does not fall back to the IP address when that returnsfalse. Those rows are also re-selected forever.Fix: treat a missing answer as an empty result and fall through to
gethostbyaddr(), then store the address itself when nothing resolves, matching what the no-resolver branch already does.