NAME
Net::DNS::ZoneCheck -- validate a DNS zone composed of RR records
SYNOPSIS
use Net::DNS::ZoneCheck;
Net::DNS::ZoneCheck::check(\@rrs, $zone);
Net::DNS::ZoneCheck::check(records => \@rrs, zone => $zone, %other_parameters);
my ($changed_records, $added_records, $deleted_records) =
Net::DNS::ZoneCheck::compare(\@rrs1, \@rrs2);
DESCRIPTION
The module assumes that it deals with well-formed Net::DNS::RR records. That is, there are no checks to ensure that the records themselves are correct. For example, no provisions are made to make sure that Net::DNS::RR::A record contains a valid IP address. This is supposed to be done beforehand by some other means.
NOTE
Please note, that API of the module as of version 0.01 is in flux and incompatible changes may be introduced in the future versions.
check
The check() sub takes the following named parameters:
- zone
-
A name of the zone being checked. This is a required parameter.
- records
-
A reference to an array of Net::DNS::RR records representing zone contents. This is a required parameter.
- on_error
-
Optional parameter, the default value is undef. For the description see section about error handling below.
- soft_error
-
Optional parameter, the default value is false. For the description see section about error handling below.
- quiet
-
Optional parameter, the default value is false. For the description see section about error handling below.
- strict_checks
-
Optional parameter, the default value is false. If set to true, check() will also perform some checks for conditions that strictly speaking are not errors, but which better to avoid nevertheless.
- relaxed_checks
-
Optional parameter, the default value is false. If set to true, check() will not perform some checks for conditions which are not very critical. If strict_checks is set, relaxed_checks is assumed to be false, whether it is specified or not.
- network_checks
-
Optional parameter, the default value is false. If set to true, check() will perform some checks which involve DNS lookups.
It is also possible, if no other parameters are specified, to call check() using positional parameters as
check($records, $zonename);
The check() function goes through zone records and performs the following checks:
- -
-
that any SOA records are defined for the zone;
- -
-
that there is exactly one SOA record;
- -
-
that SOA record is indeed an SOA record for this zone;
- -
-
that there are some NS records;
- -
-
that all NS records are inside this zone;
- -
-
that NS records do not point to an IP address (can be skipped with relaxed_checks);
- -
-
that NS records will be visible, which might not be the case because of delegations (can be skipped with relaxed_checks);
- -
-
that, if an NS record points outside of the zone itself, a successful DNS lookup for the corresponding A record can be made (only done when network_checks is true);
- -
-
that, if an NS record points inside the zone, it points to an existing A record (can be skipped with relaxed_checks);
- -
-
that, if an NS record is a subzone delegation that points to the subzone itself or inside the subzone, a corresponding "glue" A-record exists (can be skipped with relaxed_checks);
- -
-
that there are at least two NS records for the zone itself and for every subzone (only done when strict_checks is true);
- -
-
that there are no duplicate identical records (only done when strict_checks is true);
- -
-
that records with identical name and type do not have different TTLs (only done when strict_checks is true);
- -
-
that there are no records with names outside of the zone;
- -
-
that there are no "invisible" records due to existing delegations (can be skipped with relaxed_checks);
- -
-
that there is no "CNAME and other data" condition;
- -
-
that there are no multiple CNAME records with the same name (this is in fact a particular case of "CNAME and other data" condition);
- -
-
that a CNAME record does not point to an IP address (can be skipped with relaxed_checks);
- -
-
that a CNAME record does not point to a non-existing record inside the zone;
- -
-
that a CNAME record does not point to another CNAME record inside the zone (can be skipped with relaxed_checks);
- -
-
that a CNAME record points to an A record (the previous condition is an exception from this, if relaxed_checks is true);
- -
-
that an MX record does not point to an IP address (can be skipped with relaxed_checks);
- -
-
that an MX record does not point to a non-existing record inside the zone;
- -
-
that an MX record does not point to a CNAME record inside the zone (can be skipped with relaxed_checks);
- -
-
that an MX record points to an A record (the previous condition is an exception from this, if relaxed_checks is true);
- -
-
that a PTR record does not point to an IP address (can be skipped with relaxed_checks);
- -
-
that a PTR record does not point to an IN-ADDR.ARPA or IP6.INT zone.
It is expected that more checks will be added in the future.
Error handling
The error handling provided by check()
is simplistic, but convoluted. There are three parameters that control what exactly happens when an error occurs, on_error, soft_errors, and quiet. The on_error parameter allows the caller to specify a custom error handler. If it is set, it is always called on any error. When called, it is passed a hash, in which three key-value pairs are of relevance: error, a textual description of the error, error_record, a DNS::RR which is related to the error, if applicable, and zone, a name of the zone passed by the caller of check()
. The interplay of on_error, soft_errors, and quiet is best described by the following table:
on_error is set
quiet true false !exist
soft_errors
true return warn & return return
false die warn & die die
!exist return warn & return return
on_error is not set
quiet true false !exist
soft_errors
true return warn & return warn & return
false die warn & die warn & die
!exist die warn & die warn & die
The values of both soft_errors and quiet when they are not specified are effectively reset to true if on_error is set (compare true/true and !exist/!exist in the first table). The author thinks that this behavior is the most sensible (remember that on_error is always called when set).
compare
The compare
sub takes two parameters which must be references to arrays of Net::DNS::RR records. It is assumed that both parameters represent the same zone, probably at different moments of time. The subroutine determines what records were added, removed, and modified in the second input array in comparison with the first. It returns three values representing the changed records, the added records, and the removed records. The last two returned values are references to arrays of Net::DNS::RR records, while the returned value for that represents modified records is a reference to an array of references to hashes, each containing exactly two pairs: one old key with a Net::DNS::RR record from the first input parameter, and another with new key with a Net::DNS::RR record from the second input parameter.
HISTORY
The basic module functionality was first described as a collection of small examples in my talk "Keeping your DNS sane with Perl" presented at Nordic Perl Workshop 2004 in Copenhagen. Nicholas Clark suggested to me to make a module out of it.
COPYRIGHT AND LICENSE
Copyright 2004 by Anton Berezin
"THE BEER-WARE LICENSE" (Revision 42)
<tobez@tobez.org> wrote this module. As long as you retain this notice
you can do whatever you want with this stuff. If we meet some day, and
you think this stuff is worth it, you can buy me a beer in return.
Anton Berezin
CREDITS
This module was largely inspired by a module of a similar functionality implemented by me for catpipe Systems ApS as a part of a DNS management system for France Telecom.
SEE ALSO
Net::DNS(3), Net::DNS::RR(3), Net::DNS::ZoneFile(3), Net::DNS::ZoneFile::Fast(3).