tinydns/analyze_dns_datafile.pl
2017-02-21 02:35:57 +01:00

460 lines
12 KiB
Perl
Executable File

#!/usr/bin/perl -w
use strict;
use Fcntl qw(:DEFAULT :flock);
use Symbol qw(gensym);
use Getopt::Std;
use IO::File;
use File::Basename;
use Cwd;
use vars qw/$opt_a $opt_b $opt_d $opt_e $opt_h $opt_m $opt_o $opt_q/;
my $zonefile_suffixi_default = "file";
my $outfile_default = "data_dns";
my $out_data_file = "nsdata.txt";
## - hashes to store the records at all, but also
## - domains, maildomains and the defined hosts
## -
my %doms = ();
my %maildoms = ();
my %hosts = () ;
my %records = () ;
## - filehandle
## -
my $fh = new IO::File ;
getopts('ab:d:e:hmo:q') || &usage();
&usage if defined $opt_h ;
my $i;
if (! defined $opt_q) {
print "\n command invoked: $0";
foreach $i (@ARGV) {
print " $i";
}
print "\n\n";
}
my $backup = defined($opt_b) ? $opt_b : 1;
if ( $backup != 1 && $backup != 0 ) {
print "\n wrong value for flag -b : $opt_b";
&usage;
}
exit ( &main(@ARGV) );
sub main {
my $infile = shift || return usage();
-f $infile or die "$infile: $!";
my $base_infile = basename($infile);
my ($line, $filename);
my ( @lines, @data_file_lines, @single_file_lines );
my ( @domains, @maildomains, @hostlist, @records );
my ( $extension, $outdir, $outfile, $multiple_files, $add_files );
## - look at the programm parameters
## -
$extension = defined($opt_e) ? $opt_e : $zonefile_suffixi_default;
$outdir = defined($opt_d) ? $opt_d : "./";
## - like to work with the realpath
## -
$outdir = Cwd::abs_path($outdir);
## $outdir =~ s#^(.*)/$#$1#;
$outfile = defined($opt_o) ? $opt_o : $outfile_default;
$outfile = $outdir . "/" . $outfile;
$multiple_files = defined($opt_m) ? 1 : 0;
$add_files = defined($opt_a) ? 1 : 0;
## - Datei einlesen
## -
if ( $fh->open($infile) ) {
flock( $fh, LOCK_SH );
chomp (@lines = <$fh>);
flock( $fh, LOCK_UN );
$fh->close();
} else {
die "can't open $! for read";
}
## oder so..
## -
## open( $fh ,$infile ) or die "can't open $! for read" ;
## flock( $fh, LOCK_SH );
## @lines = <$fh>;
## flock( $fh, LOCK_UN );
## close ( $fh );
## - sichere original file
## -
&write_file($outdir . "/" . $base_infile,@lines);
## - first we push into hashes, so we can sort
## - afterwords
## -
foreach (@lines) {
## chomp ;
## - ignore emty lines
## -
next if /^\s*$/o ;
## - ignore comments
## -
next if /^#/o ;
$records{$_} = 1 ;
if ( /^([\.|\&|Z])([^:]*)(.*)$/o ) {
$doms{$2} = 1 ;
}
## - maildomain ?
## -
if ( /^(\@)([^:]*)(.*)/o) {
$maildoms{$2} = 1;
}
## - host definition ?
## -
if ( /^(\+)([^:]*)(.*)/o) {
$hosts{$2} = 1;
}
}
## - Now sort and put into the considered arrays
## -
@domains = sort ( keys %doms ) ;
@maildomains = sort ( keys %maildoms ) ;
@hostlist = sort ( keys %hosts ) ;
@records = sort ( sort_records keys %records);
## - schreibe domainliste, maildomainliste, hostliste, records
## -
if ( $add_files ) {
&write_file($outdir . "/domains.lst",@domains);
&write_file($outdir . "/maildomains.lst",@maildomains);
&write_file($outdir . "/hostlist.lst",@hostlist);
&write_file($outdir . "/records.lst",@records);
}
my $_domain ="";
my $_type;
my $_filename = 0;
foreach ( @records ) {
/(.)([^:]+).*/o ;
if ( $_domain eq get_domain($2) ) {
if ( $_type ne $1 ) {
if ( $multiple_files ) {
push ( @single_file_lines, get_record_comment($1) );
} else {
push ( @data_file_lines, get_record_comment($1) );
}
}
if ( $multiple_files ) {
push ( @single_file_lines, $_ );
} else {
push ( @data_file_lines, $_ );
}
} else {
&write_file($filename,@single_file_lines) if ($filename);
@single_file_lines = ();
$_type = "";
$_domain = get_domain($2);
if ( $multiple_files ) {
$filename = $outdir . "/" . $_domain . ".file";
push ( @single_file_lines, "## - domain: $_domain");
push ( @single_file_lines, "## - ");
push ( @single_file_lines, get_record_comment($1) );
push ( @single_file_lines, $_ );
} else {
push ( @data_file_lines, "\n" );
push ( @data_file_lines, "## - domain: $_domain");
push ( @data_file_lines, "## - ");
push ( @data_file_lines, get_record_comment($1) );
push ( @data_file_lines, $_ );
}
}
$_type = $1;
}
if ( $multiple_files ) {
## - letztes file muss noch geschrieben werdem
## -
&write_file($filename, @single_file_lines);
} else {
## - schreibe alles in ein file
## -
&write_file($outfile, @data_file_lines);
}
exit 0
}
sub get_domain {
my $record = shift ;
if ( $doms{$record} ) {
return $record ;
} else {
while ( $record =~ /([^\.]*).(.*)/o ) {
if ( $doms{$2} ) {
return $2;
}
$record = $2;
}
}
return 1 ;
}
sub get_record_comment {
my $directive_type = shift;
my $comment;
SWITCH : {
$1 eq "Z" and $comment = "## - SOA" , last SWITCH;
$1 eq "." and $comment = "## - SOA, NS, A" , last SWITCH;
$1 eq "&" and $comment = "## - NS, A" , last SWITCH;
$1 eq "@" and $comment = "## - MX, A" , last SWITCH;
$1 eq "=" and $comment = "## - A, PTR" , last SWITCH;
$1 eq "+" and $comment = "## - A" , last SWITCH;
$1 eq "C" and $comment = "## - CNAME" , last SWITCH;
$1 eq "^" and $comment = "## - PTR" , last SWITCH;
$1 eq "'" and $comment = "## - TEXT" , last SWITCH;
$1 eq "3" and $comment = "## - AAAA" , last SWITCH;
$1 eq "6" and $comment = "## - AAAA, PTR" , last SWITCH;
$comment = "## - unknown record";
}
return $comment;
}
# Datei schreiben
#
sub write_file {
my $outfile = shift ;
my @lines = @_ ;
backup($outfile) if ( -f $outfile );
if (! defined $opt_q) {
print "\twrite $outfile ..\n";
}
$fh = new IO::File "> $outfile";
if (defined $fh) {
foreach (@lines) {
print $fh $_ . "\n" ;
}
$fh->close();
}
## - oder auch so..
## -
## open ( $fh , "> $outfile") or die "can't open $! for write" ;
## print $fh @lines ;
## close ($fh);
}
#
# - backup
#
sub backup {
my $filename = shift ;
# Sicherungskopie erstellen
#
if ($backup) {
OUTER: for ( my $i = 0 ; $i < 10 ; $i++ ) {
for ( my $j = 0 ; $j < 10 ; $j++ ) {
my $backupfile = $filename . ".$i$j" ;
if ( -f $backupfile
|| -d $backupfile
|| -l $backupfile
|| -p $backupfile
|| -c $backupfile
|| -b $backupfile
|| -S $backupfile ) {
next ;
} else {
my $retval = system( "cp -f $filename $backupfile") ;
if ($retval != 0) {
die "can't store backupfile $backupfile"
}
if (! defined $opt_q) {
print "\n\tbackupfile stored in $backupfile\n";
}
last OUTER ;
}
}
} # ende OUTER : for ( ...
} # ende if
} # end backup()
sub sort_records {
my ( $rval1, $rval2, $domain_a, $domain_b, $directive_a, $directive_b );
$a =~ /(.)([^:]+).*/;
## - get directive
## -
SWITCH : {
$1 eq "Z" and $directive_a = 10 , last SWITCH;
$1 eq "." and $directive_a = 20 , last SWITCH;
$1 eq "&" and $directive_a = 30 , last SWITCH;
$1 eq "@" and $directive_a = 40 , last SWITCH;
$1 eq "=" and $directive_a = 50 , last SWITCH;
$1 eq "+" and $directive_a = 60 , last SWITCH;
$1 eq "C" and $directive_a = 70 , last SWITCH;
$1 eq "^" and $directive_a = 80 , last SWITCH;
$1 eq "'" and $directive_a = 90 , last SWITCH;
$1 eq "3" and $directive_a = 100, last SWITCH;
$1 eq "6" and $directive_a = 110, last SWITCH;
$directive_a = 999;
}
## - get domain..
## -
$domain_a = get_domain($2);
$b =~ /(.)([^:]+).*/;
## - get directive
## -
SWITCH : {
$1 eq "Z" and $directive_b = 10 , last SWITCH;
$1 eq "." and $directive_b = 20 , last SWITCH;
$1 eq "&" and $directive_b = 30 , last SWITCH;
$1 eq "@" and $directive_b = 40 , last SWITCH;
$1 eq "=" and $directive_b = 50 , last SWITCH;
$1 eq "+" and $directive_b = 60 , last SWITCH;
$1 eq "C" and $directive_b = 70 , last SWITCH;
$1 eq "^" and $directive_b = 80 , last SWITCH;
$1 eq "'" and $directive_b = 90 , last SWITCH;
$1 eq "3" and $directive_b = 100, last SWITCH;
$1 eq "6" and $directive_b = 110, last SWITCH;
$directive_b = 999;
}
## - get domain..
## -
$domain_b = get_domain($2);
$rval1 = $domain_a cmp $domain_b ;
if ( $rval1 == 0 ) {
$rval2 = $directive_a <=> $directive_b;
if ( $rval2 == 0 ) {
return $a cmp $b;
} else {
return $rval2;
}
} else {
return $rval1;
}
}
#
# - usage
#
sub usage {
my $file = basename($0);
$file =~ s#.*/([^/]+)$#$1# ;
print <<ENDE;
Usage: $file [OPTIONS] <tinydns-data-file>
This script concatinates all zonefiles with a certain fileextension
of a given directory.
This script takes all directives from a given djb tinydns-data-file,
sorts them and put the sortet list back into one data-file or, if
option "m" is set into one file for each domain, named by the concerning
domain.
A copy of the (original) inputfile will be written out in <outdir>.
Control Options:
-a The following addition files be written:
<outdir>/domains.lst.......: alphabetical list of domains
<outdir>/maildomains.lst...: alphabetical list of domains
with MX entry
<outdir>/hostlist.lst......: alphabetical list of all
hostentries (A - Record)
<outdir>/records.lst.......: all records sorted by domain but
without any comment or emty line
-b <0|1> a value of "1" means: befor writing a file backup existing one;
dont backup if "0". default value is "1"
-d <outdir> directory where the outfile(s) are written. defaults to
working directory
-e <ext> write data-files with extension <ext>. defaults to
"$zonefile_suffixi_default". only affected if option -m is set
-h prints this helpcontents
-m write one file for each domain
-o <outfile> name of outputfile. defaults to "$outfile_default". only
affect if not -m is set
-q silent output
ENDE
exit 1 ;
}