15.3. Perl Programming with Net::DNSIf 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-0.12.tar.gz.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. 15.3.1. Resolver ObjectsBefore making any queries, you must first create a resolver object:
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"); 15.3.2. Packet ObjectsResolver queries return Net::DNS::Packet objects, whose methods you can use to access the header, question, answer, authority, and additional sections of a DNS message:
$header = $packet->header; @question = $packet->question; @answer = $packet->answer; @authority = $packet->authority; @additional = $packet->additional; 15.3.3. Header ObjectsDNS message 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"; } 15.3.4. Question ObjectsThe question section of a DNS message 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 15.3.5. Resource Record ObjectsThe answer, authority, and additional sections of a DNS message 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:
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; 15.3.6. A Perl Version of check_soaNow 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:
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"; }
|
|