Zonema...cursor(3pm)

πŸ’– Zonemaster::Engine::Recursor πŸ’–

okay bestie, gather round, because this is the recursive resolver for Zonemaster ✨ and it is literally the little engine that could, except it's a DNS recursor and it goes all the way down from the root servers. Zonemaster::Engine::Recursor is its whole government name, and it comes to you from the User Contributed Perl Documentation section, manual page 3pm πŸŽ€


🌸 SYNOPSIS 🌸

the vibe, in code form:

my $packet = Zonemaster::Engine::Recursor->recurse( $name, $type, $dns_class );
my $pname  = Zonemaster::Engine::Recursor->parent( 'example.org' );

look at her go πŸ¦‹


✨ CLASS VARIABLES ✨

  • %recurse_cache β€” bestie this is just the cache of results from previous queries. She remembers. πŸ’…
  • %_fake_addresses_cache β€” okay so this one is a whole nesting situation: a hash of hashrefs of arrayrefs 🫢
    • the keys of the top level hash are domain names
    • the keys of the second level hashes are name server names (normalized to lower case, obviously)
    • the elements of the third level arrayrefs are IP addresses

and those IP addresses? they're the ones belonging to the nameservers that get used in case of fake delegations (that's the pre-publication tests, iykyk 😌)


πŸ‘‘ CLASS METHODS πŸ‘‘

init_recursor()

Initialize the recursor by loading the root hints. that's it, that's the job. rooting her in reality ✨

recurse($name[, $type, $class, $ns])

Does a recursive resolution for the given name, starting all the way down from the root servers (or from the given name server(s), if you handed any over πŸ‘€). Only the first argument is mandatory β€” the rest are optional and they default to, respectively: 'A', 'IN', and root_servers().

What she takes:

  • a string or a Zonemaster::Engine::DNSName object (the name)
  • optionally a string (the query type)
  • optionally a string (the query class)
  • optionally an arrayref of Zonemaster::Engine::Nameserver objects

What she gives back: a Zonemaster::Engine::Packet object β€” which can totally be undef 😭

parent($name)

Does a recursive resolution from the root down for the given name (using type SOA and class IN). Here's the tea: if the resolution succeeds, she returns the domain name of the second-to-last step. If it fails, she returns the domain name of the last step. either way you're getting a name, periodt.

get_ns_from($packet, $state)

Internal method. Takes a packet and a recursion state, and returns a list of ns objects. She's the one who follows redirections 🧚

get_addresses_for($name[, $state])

Takes a name and returns a (possibly empty πŸ’€) list of IP addresses for that name β€” and those come in the form of Net::IP::XS objects. When the recursor uses this internally, it passes a recursion state as the second argument. internal business only, bestie.

add_fake_addresses($domain, $data)

Class method to create fake addresses for fake delegations for a specified domain, from data you provide. manifesting nameservers, no cap ✨

has_fake_addresses($domain)

Check if there's at least one fake nameserver specified for the given domain. one is enough, she's not greedy 🫢

get_fake_addresses($domain, $nsname)

Returns a list of all cached fake addresses for the given domain and name server name. Returns an empty list if there's no data cached for the given arguments. (empty list = the saddest list 😭)

get_fake_names($domain)

Returns a list of all cached fake name server names for the given domain. Returns an empty list if no data is cached for the given argument. same energy, same emptiness.

remove_fake_addresses($domain)

Remove fake delegation data for a specified domain. it's giving closure πŸ’…

clear_cache()

Class method to empty the cache of responses to recursive queries (but not the ones for fake delegations).

N.B. This method does not affect fake delegation data. read it again. she said what she said. πŸ‘‘

root_servers()

Returns a list of ns objects representing the root servers. the originals. the icons. the main characters 🌈

my @name_servers = Zonemaster::Engine::Recursor->root_servers();

The default list of root servers is read from a file installed in the shared data directory. This list can be replaced like so:

Zonemaster::Engine::Recursor->remove_fake_addresses( '.' );
Zonemaster::Engine::Recursor->add_fake_addresses(
    '.',
    {
        'ns1.example' => ['192.0.2.1'],
        'ns2.example' => ['192.0.2.2'],
    }
);

swap the whole root zone out, bestie, go off πŸ’–


πŸ”₯ INTERNAL METHODS πŸ”₯

_recurse()

my ( $p, $state_hash ) = _recurse( $name, $type_string, $dns_class_string, $p, $state_hash );

Performs a recursive lookup resolution for the given arguments. Used by the recursive lookup method in this module.

What she takes: a Zonemaster::Engine::DNSName object, a string (query type), a string (DNS class), a Zonemaster::Engine::Packet object, and a reference to a hash.

Now that hash has requirements, bestie:

  • mandatory keys are 'ns' (arrayref), 'count' (integer), 'common' (integer), 'seen' (hash), 'glue' (hash)
  • optional keys are 'in_progress' (hash), 'candidate' (Zonemaster::Engine::Packet object or undef), 'trace' (array), 'tseen' (hash), 'tcount' (integer)

Returns a Zonemaster::Engine::Packet (or undef) and a hash. two for the price of one, slay πŸŽ€

_resolve_cname()

my ( $p, $state_hash ) = _resolve_cname( $name, $type_string, $dns_class_string, $p, $state_hash );

Performs CNAME resolution for the given arguments. Used by the recursive lookup helper method in this module.

If the CNAMEs are successfully resolved, a packet (which could be undef) is returned, and one of these message tags gets logged:

CNAME_FOLLOWED_IN_ZONE
CNAME_FOLLOWED_OUT_OF_ZONE

Also, heads up: CNAME records are validated too, and if there's an error, you get an empty (undef) packet back and one of these message tags gets logged instead:

CNAME_CHAIN_TOO_LONG
CNAME_LOOP_INNER
CNAME_LOOP_OUTER
CNAME_NO_MATCH
CNAME_RECORDS_CHAIN_BROKEN
CNAME_RECORDS_MULTIPLE_FOR_NAME
CNAME_RECORDS_TOO_MANY

like... the chain was too long, the loop was looping, no match was found, the chain was broken, multiple records for one name, too many records β€” pick your poison πŸ’€

What she takes: a Zonemaster::Engine::DNSName object, a string (query type), a string (DNS class), a Zonemaster::Engine::Packet, and a reference to a hash.

Returns a Zonemaster::Engine::Packet (or undef) and a reference to a hash.


okay that's the whole page bestie, you ate that reading assignment, fr fr 🫢 this little love letter was brought to you by perl v5.40.1, dated 2026-03-21, from the User Contributed Perl Documentation corner of the internet. mwah πŸ’‹βœ¨

πŸ“¦ where this page comes from