Net::DNS treats resolvers, DNS messages, sections of DNS messages, and individual resource records as objects and provides methods for setting or querying each object's attributes. We'll examine each object type first, then give a Perl version of our check_soa program.
Resolver objects are initialized from your resolv.conf file, but you can change the default settings by making calls to the object's methods. Many of the methods described in the Net::DNS::Resolver manual page correspond to fields and options in the _res structure described earlier in this chapter. For example, if you want to set the number of times the resolver tries each query before timing out, you can call the $res->retry method:$res = new Net::DNS::Resolver;
To make a query, call one of the following methods:$res->retry(2);
These methods behave like the res_search, res_query, and res_send library functions described in the C programming section, though they take fewer arguments. You must provide a domain name, and you can optionally provide a record type and class (the default behavior is to query for A records in the IN class). These methods return Net::DNS::Packet objects, which we'll describe next. Here are a few examples:$res->search $res->query $res->send
$packet = $res->search("terminator"); $packet = $res->query("movie.edu", "MX"); $packet = $res->send("version.bind", "TXT", "CH");
$header = $packet->header; @question = $packet->question; @answer = $packet->answer; @authority = $packet->authority; @additional = $packet->additional;
if ($header->aa) { print "answer is authoritative\n"; } else { print "answer is not authoritative\n"; }
$question->qname $question->qtype $question->qclass
Each record type is a subclass of Net::DNS::RR and has its own type-specific methods. Here's an example that shows how to get the preference and mail exchanger out of an MX record:$rr->name $rr->type $rr->class $rr->ttl
$preference = $rr->preference; $exchanger = $rr->exchange;
Now that you've seen how to write a DNS program using a shell script, a Perl script, and C code, you should be able to write one on your own using the language that best fits your situation.#!/usr/local/bin/perl -w use Net::DNS; #---------------------------------------------------------------------- # Get the zone from the command line. #---------------------------------------------------------------------- die "Usage: check_soa zone\n" unless @ARGV == 1; $domain = $ARGV[0]; #---------------------------------------------------------------------- # Find all the name servers for the zone. #---------------------------------------------------------------------- $res = new Net::DNS::Resolver; $res->defnames(0); $res->retry(2); $ns_req = $res->query($domain, "NS"); die "No name servers found for $domain: ", $res->errorstring, "\n" unless defined($ns_req) and ($ns_req->header->ancount > 0); @nameservers = grep { $_->type eq "NS" } $ns_req->answer; #---------------------------------------------------------------------- # Check the SOA record on each name server. #---------------------------------------------------------------------- $| = 1; $res->recurse(0); foreach $nsrr (@nameservers) { #------------------------------------------------------------------ # Set the resolver to query this name server. #------------------------------------------------------------------ $ns = $nsrr->nsdname; print "$ns "; unless ($res->nameservers($ns)) { warn ": can't find address: ", $res->errorstring, "\n"; next; } #------------------------------------------------------------------ # Get the SOA record. #------------------------------------------------------------------ $soa_req = $res->send($domain, "SOA"); unless (defined($soa_req)) { warn ": ", $res->errorstring, "\n"; next; } #------------------------------------------------------------------ # Is this name server authoritative for the zone? #------------------------------------------------------------------ unless ($soa_req->header->aa) { warn "is not authoritative for $domain\n"; next; } #------------------------------------------------------------------ # We should have received exactly one answer. #------------------------------------------------------------------ unless ($soa_req->header->ancount == 1) { warn ": expected 1 answer, got ", $soa_req->header->ancount, "\n"; next; } #------------------------------------------------------------------ # Did we receive an SOA record? #------------------------------------------------------------------ unless (($soa_req->answer)[0]->type eq "SOA") { warn ": expected SOA, got ", ($soa_req->answer)[0]->type, "\n"; next; } #------------------------------------------------------------------ # Print the serial number. #------------------------------------------------------------------ print "has serial number ", ($soa_req->answer)[0]->serial, "\n"; }