#

| Chapter 14 Programming with the Resolver and Name Server Library Routines |

## 14.3 Perl Programming with Net::DNS

If using the shell to parse `nslookup`'s output seems too awkward and writing a C program seems too complicated, consider writing your program in Perl using the Net::DNS module written by Michael Fuhr. You'll find the package at http://www.perl.com/CPAN-local/modules/by-module/Net/.

Net::DNS treats resolvers, DNS packets, sections of DNS packets, 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.

### 14.3.1 Resolver Objects

Before making any queries, you must first create a resolver object:

>     $res = new Net::DNS::Resolver;

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 of the _res structure described earlier in the C programming section. 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->retry(2);

To make a query, call one of the following methods:

>     $res->search
>     $res->query
>     $res->send

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 name, and you can optionally provide a DNS 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 shortly. Here are a few examples:

>     $packet = $res->search("terminator");
>     $packet = $res->query("movie.edu", "MX");
>     $packet = $res->send("version.bind", "TXT", "CH");

### 14.3.2 Packet Objects

Resolver queries return Net::DNS::Packet objects, whose methods you can use to access the header, question, answer, authority, and additional sections of a DNS packet:

>     $header     = $packet->header;
>     @question   = $packet->question;
>     @answer     = $packet->answer;
>     @authority  = $packet->authority;
>     @additional = $packet->additional;

### 14.3.3 Header Objects

DNS packet headers are returned as Net::DNS::Header objects. The methods described in the Net::DNS::Header manual page correspond to the header fields described in RFC 1035 and in the HEADER structure used in C programs. For example, if you want to find out if this is an authoritative answer, you would call the $header->aa method:

>     if ($header->aa) {
>         print "answer is authoritative\n";
>     } else {
>         print "answer is not authoritative\n";
>     }

### 14.3.4 Question Objects

The question section of a DNS packet is returned as a list of Net::DNS::Question objects. You can find the name, type, and class of a question object with the following methods:

>     $question->qname
>     $question->qtype
>     $question->qclass

### 14.3.5 Resource Record Objects

The answer, authority, and additional sections of a DNS packet are returned as lists of Net::DNS::RR objects. You can find the name, type, class, and TTL of an RR object with the following methods:

>     $rr->name
>     $rr->type
>     $rr->class
>     $rr->ttl

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 exchange out of an MX record:

>     $preference = $rr->preference;
>     $exchange   = $rr->exchange;

### 14.3.6 A Perl Version of check_soa

Now that we've described the objects Net::DNS uses, let's look at how to use them in a complete program. We've rewritten check_soa in Perl:

>     #!/usr/local/bin/perl -w

>     use Net::DNS;

>     #----------------------------------------------------------------------
>     # Get the domain from the command line.
>     #----------------------------------------------------------------------

>     die "Usage:  check_soa domain\n" unless @ARGV == 1;
>     $domain = $ARGV[0];

>     #----------------------------------------------------------------------
>     # Find all the nameservers for the domain.
>     #----------------------------------------------------------------------

>     $res = new Net::DNS::Resolver;

>     $res->defnames(0);
>     $res->retry(2);

>     $ns_req = $res->query($domain, "NS");
>     die "No nameservers 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 nameserver.
>     #----------------------------------------------------------------------

>     $| = 1;
>     $res->recurse(0);

>     foreach $nsrr (@nameservers) {

>       #------------------------------------------------------------------
>       # Set the resolver to query this nameserver.
>       #------------------------------------------------------------------

>       $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 nameserver authoritative for the domain?
>       #------------------------------------------------------------------

>       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";
>     }

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.

14.2 C Programming with the Resolver Library Routines |  | 15. Miscellaneous