#!/usr/bin/perl -w

use strict;
use utf8;
use warnings;

use Net::DNS::Resolver ();

use Getopt::Long;

my %Option;
GetOptions(
    'debug!'             => \( my $Debug = 0 ),
    'exclude-toplevel=s' => \my @TopLevel,
    'resolver-option=s'  => ( $Option{resolver} = {} ),
);

$| = 1;

my @errors;
print 'Checking Domains', "\n" if $Debug;
while (<>) {
    chomp;
    my $domain = $_;
    print "  $domain... " if $Debug;

    if (@TopLevel) {
        my @host = split /\./, $domain;
        my $tld = $host[-1];
        if ( grep( /^$tld$/, @TopLevel ) ) {
            print 'skipping!', "\n" if $Debug;
            next;
        }
    }
    my $result = check_ns_records( $domain, %Option );
    print $result || 'OK', "\n" if $Debug;
    push @errors, "$domain... $result" if $result;
}
if (@errors) {
    print join( ', ', @errors ), "\n";
    exit 2;
}

print "All NS records OK\n";
exit 0;

my $_res;
my %already_checked;
sub check_ns_records {
    my ( $zone, %option ) = @_;

    my $res = $_res || Net::DNS::Resolver->new(%option);
    $res->debug( $option{debug} ) if $option{debug};

    my $ns_packet = $res->query( $zone, 'NS' );
    return 'no NS Records' unless $ns_packet;

    my $found_a     = 0;
    my $found_other = 0;
    foreach my $ns ( grep { $_->type eq 'NS' } $ns_packet->answer ) {

        my $nsd_name = $ns->nsdname;
        unless ( exists $already_checked{$nsd_name} ) {
            my $nsa_packet = $res->query( $nsd_name );
            return "no answer for NS Record for $nsd_name" unless $nsa_packet;
            foreach my $nsa ( $nsa_packet->answer ) {
                if ( $nsa->type eq 'A' || $nsa->type eq 'AAAA' ) {
                    $found_a = 1;
                }
                else {
                    $found_other = 1;
                }
            }
            $already_checked{$nsd_name} = [ $found_a, $found_other ];
        }
        $found_a     = $already_checked{$nsd_name}->[0];
        $found_other = $already_checked{$nsd_name}->[1];
    }

    return ''          if $found_a && !$found_other;
    return 'found non-A-Records'        if $found_other;
    return 'did not find any A-Records' if !$found_a;

    return "Unknown Problem: ( $found_a, $found_other )";
}

__END__

=encoding utf8

=head1 NAME

check.dns_records - Überprüft die NS-RRs von Domains

=head1 SYNOPSE

    gen.domain -domainstatus OK -kunde adidas -template liste |
    sort |
    check.dns_records -resolver udp_timeout=5

=head1 BESCHREIBUNG

Das Programm erwartet in den namentlich auf der Kommandozeile angegebenen
Dateien oder auf der Standardeingabe Listen, die pro Zeile jeweils eine
Domain enthält.

Es prüft dann für jede Domain ob der NS-Record einen A-Record beinhaltet.
Eventuelle Abweichungen werden gemeldet.

=head1 OPTIONEN

=over 4

=item resolver-option NAME=WERT

um Optionen direkt an den L<Net::DNS::Resolver> zu übergeben, der für die
lokale Namensauflösung verwendet wird

=item exclude-toplevel TLD

um bestimmte TLDs von der Prüfung auszuschliessen.

=item -help

=item -?

um (nur) diese Dokumentation anzeigen zu lassen

=back

=cut

=head1 AUTOR

 Stelios Gikas <stelios.gikas@noris.de>
 Stelios Gikas <16466101@ticket.noris.net>
 für die noris network AG

