1#!/usr/bin/perl
2#
3# $Id: Consistency.pm 749 2009-03-20 09:22:13Z calle $
4#
5# Copyright (c) 2007 .SE (The Internet Infrastructure Foundation).
6#                    All rights reserved.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28#
29######################################################################
30
31package DNSCheck::Test::Consistency;
32
33require 5.008;
34use warnings;
35use strict;
36
37our $SVN_VERSION = '$Revision: 749 $';
38
39use base 'DNSCheck::Test::Common';
40
41use Net::IP 1.25;
42use Digest::SHA1 qw(sha1 sha1_hex sha1_base64);
43
44######################################################################
45
46sub test {
47    my $self = shift;
48    my $zone = shift;
49
50    my $parent = $self->parent;
51    my $qclass = $self->qclass;
52    my $logger = $self->logger;
53    my $errors = 0;
54
55    return unless $parent->config->should_run;
56
57    $logger->module_stack_push();
58    $logger->auto("CONSISTENCY:BEGIN", $zone);
59
60    my %serial_counter;
61    my %digest_counter;
62    my %nameservers = ();
63
64    # fetch all nameservers, both from parent and child
65    my @ns_parent = $parent->dns->get_nameservers_at_parent($zone, $qclass);
66    my @ns_child = $parent->dns->get_nameservers_at_child($zone, $qclass);
67
68    foreach my $ns (@ns_parent, @ns_child) {
69        foreach my $address ($parent->dns->find_addresses($ns, $qclass)) {
70            my $ip = new Net::IP($address);
71
72            if ($ip->version == 4 and $parent->config->get("net")->{ipv4}) {
73                $nameservers{$address} = $address;
74            }
75
76            if ($ip->version == 6 and $parent->config->get("net")->{ipv6}) {
77                $nameservers{$address} = $address;
78            }
79        }
80    }
81
82    foreach my $address (keys %nameservers) {
83        my $packet =
84          $parent->dns->query_explicit($zone, $qclass, "SOA", $address);
85
86        next unless ($packet);
87
88        foreach my $rr ($packet->answer) {
89            next unless ($rr->type eq "SOA");
90
91            my $serial = $rr->serial;
92
93            my $digest = sha1_hex(
94                join(':',
95                    $rr->mname, $rr->rname,  $rr->refresh,
96                    $rr->retry, $rr->expire, $rr->minimum)
97            );
98
99            $logger->auto("CONSISTENCY:SOA_SERIAL_AT_ADDRESS",
100                $address, $serial);
101            $logger->auto("CONSISTENCY:SOA_DIGEST_AT_ADDRESS",
102                $address, $digest);
103
104            $serial_counter{$serial}++;
105            $digest_counter{$digest}++;
106        }
107    }
108
109    my $unique_serials = scalar keys %serial_counter;
110    my $unique_digests = scalar keys %digest_counter;
111
112    if ($unique_serials > 1) {
113        $logger->auto("CONSISTENCY:SOA_SERIAL_DIFFERENT", $unique_serials);
114    } else {
115        $logger->auto("CONSISTENCY:SOA_SERIAL_CONSISTENT");
116    }
117
118    if ($unique_digests > 1) {
119        $logger->auto("CONSISTENCY:SOA_DIGEST_DIFFERENT", $unique_digests);
120    } else {
121        $logger->auto("CONSISTENCY:SOA_DIGEST_CONSISTENT");
122    }
123
124  DONE:
125    $logger->auto("CONSISTENCY:END", $zone);
126    $logger->module_stack_pop();
127
128    return 0;
129}
130
1311;
132
133__END__
134
135
136=head1 NAME
137
138DNSCheck::Test::Consistency - Test zone consistency
139
140=head1 DESCRIPTION
141
142Test zone consistency. The following tests are made:
143
144=over 4
145
146=item *
147The serial number of the zone must be the same at all listed name servers.
148
149=back
150
151=head1 METHODS
152
153=over
154
155=item ->test($zonename)
156
157Check that the SOA records retrieved from all nameservers for the zone contain
158the same information (that is, the same serial number and the same timeout
159values).
160
161=back
162
163=head1 EXAMPLES
164
165=head1 SEE ALSO
166
167L<DNSCheck>, L<DNSCheck::Logger>
168
169=cut
170