#!/usr/bin/perl -w

BEGIN {
    unshift( @INC, ( $ENV{POPHOME} || '@POPHOME@' ) . '/lib' )
      unless $ENV{KUNDE_NO_PERLPATH};
}

use utf8;
use strict;
use warnings;

use Cf qw($DNS_PROXIES);
use Dbase::Getopt qw(:DEFAULT);
use Dbase::IP;
use noris::DNS::Resolver;
use Socket qw(AF_INET AF_INET6);
use Socket6 qw(gethostbyname2 inet_ntop);

my %Check;

sub getopt_check {
    my ( $option, $value ) = @_;
    $Check{$option} = $value;
}

@ARGV = GetOptions(
    'fix-in-dns!' => \my $FixInDns,
    'forward!'    => \&getopt_check,
    'reverse!'    => \&getopt_check,
    'verbose+'    => \my $Verbose,
);

my $resolver = noris::DNS::Resolver->new;

$| = 1;
while (<>) {
    chomp;
    my ( $kunde, $ip6, $fqdn ) = split /\t/;

    my $ip = Dbase::IP->new($ip6) or die "Invalid IP address: $ip6\n";

    if ( $Check{forward} ) {
        my $s = "$kunde: $fqdn [$ip]: ";
        unless (
            my ( $h_name, $h_aliases, $h_addrtype, $h_length, @h_addr_list ) =
            $ip->is_v4
            ? gethostbyname($fqdn)
            : gethostbyname2( $fqdn, AF_INET6 )
          )
        {
            print $s . "No DNS entry for this FQDN.\n";
        }
        else {
            $_ =
              Dbase::IP->new(
                inet_ntop( length() == 4 ? AF_INET: AF_INET6, $_ ) )->str
              for @h_addr_list;

            unless ( grep $_ eq $ip->str, @h_addr_list ) {
                print $s. "DNS differs: " . join( ', ', @h_addr_list ) . "\n";
            }
            elsif ($Verbose) {
                print $s. join( ', ', @h_addr_list ) . "\n";
            }
        }
    }

    if ( !keys %Check || $Check{reverse} ) {
        my $s = "$kunde: $ip: ";
        my %name;
        {
            my $packet = $resolver->send("$ip");
            @name{ map $_->type eq 'PTR' ? lc $_->ptrdname : (),
                $packet->answer } = ();
        }
        unless ( exists $name{ lc $fqdn } ) {
            print "$s$fqdn\@DB", keys %name > 0
              && ' vs. ' . join( '/', sort keys %name ) . '@DNS', "\n";
            if ( $FixInDns && !keys %name ) {
                unless ( open my $fh, ( my $nsset = "| nsset -a -r $ip" ) ) {
                    die "open('$nsset'): $!\n";
                }
                else {
                    print $fh "PTR $fqdn\n";
                    close $fh;
                }
            }
        }
        elsif ($Verbose) {
            print "$s$fqdn\@DB", keys %name == 1 ? '+DNS' : ', ',
              join( '/', sort keys %name ) . '@DNS', "\n";
        }
    }

}

__END__

=encoding utf8

=head1 NAME

obsolete_FQDNs - Abweichungen von FQDNs zwischen Datenbank und DNS finden

=head1 SYNOPSE

    t=/usr/share/doc/kunde/examples/templates/gen.ip/obsolete_FQDNs

    gen.ip -template "$t" | sort | obsolete_FQDNs | grep ' (DNS master for '

=head1 BESCHREIBUNG

Das Programm erwartet auf der Standardeingabe eine zeilenweise Liste, wobei jede
Zeile aus drei durch Tabs getrennten Feldern bestehen muss:

=over 4

=item 1.

Kundenname oder anderer Schlüsselwert, der später mit ausgegeben wird, um die
Zuordung zu erleichtern

=item 2.

Host-IP-Adresse

=item 3.

in der Datenbank eingetragener FQDN

=back

Das Programm untersucht dann für alle angegebenen IP-Adressobjekte, ob der dort
eingetragene FQDN mit dem im DNS eingetragenen übereinstimmt und gibt dabei alle
Fälle aus, bei denen das nicht der Fall ist oder bei denen im DNS gar kein
Reverse Lookup konfiguriert ist.

=head1 OPTIONEN

=over 4

=item -fix-in-dns

fehlende(!) Eintragungen im DNS nach Möglichkeit automatisch ergänzen

=item -forward

Vorwärtsauflösung (A- und AAAA-RRs) überprüfen

=item -reverse

Rückwärtsauflösung (PTR-RRs) überprüfen (Default)

=item -verbose

auch die untersuchten Fälle ausgeben, bei denen keine Inkonsistenz gefunden
wurde

=item -help

=item -?

um (nur) diese Dokumentation anzeigen zu lassen

=back

