Skip to content

Addresses with no PTR record are re-queried on every resolver pass #353

Description

@somethingwithproof

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions