vidns
changeset 2 1e26b0942c13
parent 1 5f07e5c283c1
child 3 5db700038f68
equal deleted inserted replaced
1:5f07e5c283c1 2:1e26b0942c13
     2 use 5.010;
     2 use 5.010;
     3 use strict;
     3 use strict;
     4 use warnings;
     4 use warnings;
     5 use File::Temp;
     5 use File::Temp;
     6 use Smart::Comments;
     6 use Smart::Comments;
       
     7 use Digest::SHA qw(sha512_hex);
     7 
     8 
     8 sub parse {
     9 sub parse {
     9     my $file = shift;
    10     my $file = shift;
    10     my @lines = split /\n/, do { 
    11     my @lines = split /\n/, do { 
    11 	local $/ = undef;
    12 	local $/ = undef;
    12 	local @ARGV = $file;
    13 	local @ARGV = $file;
    13 	<>;
    14 	<>;
    14     };
    15     };
    15 
    16 
    16     my @zone;
    17     my @zone;
       
    18     my ($origin, $ttl, $last_label);
    17 
    19 
    18     foreach (@lines) {
    20     foreach (@lines) {
       
    21 	s{;.*$}{};
    19         given ($_) {
    22         given ($_) {
    20             when (m{^;}) { next }
    23 	    when (m{^\s*\$ORIGIN\s+(\S+)}) { $origin = $1 }
       
    24 	    when (m{^\s*\$TTL\s+(\S+)}) { $ttl = $1 }
    21             when (
    25             when (
    22                 m{^(?<label>\S+)
    26                 m{^(?<label>\S+)?
    23 		    \s+(?<ttl>\S+(?=\s+))
    27 		    \s+(?<ttl>\S+(?=\s+))
    24 		    \s+(?:(?:IN|ANY)\s+)?(?<rr>\S+(?=\s+))
    28 		    \s+(?:(?:IN|ANY)\s+)?(?<rr>\S+(?=\s+))
    25 		    \s+(?<data>.*)
    29 		    \s+(?<data>.*)
    26 		  }x
    30 		  }x
    27               )
    31               )
    28             {
    32             {
    29 		push @zone, {
    33 		my %rrset = (
    30                         label => $+{label},
    34                         label => $last_label = defined $+{label} 
    31                         ttl   => $+{ttl},
    35 				? $+{label} eq '@' ?  $origin : $+{label}
       
    36 				: $last_label,
       
    37                         ttl   => $+{ttl} // $ttl,
    32                         rr    => uc $+{rr},
    38                         rr    => uc $+{rr},
    33                         data  => $+{data},
    39                         data  => $+{data},
    34 		};
    40 		);
       
    41 
       
    42 		# label ergänzen, wenn nicht FQDN
       
    43 		$rrset{label} .= ".$origin" unless substr($rrset{label}, -1) eq '.';
       
    44 
       
    45 		given ($rrset{rr}) {
       
    46 		    # origin steht im SOA
       
    47 		    when('SOA') { $origin = $rrset{label} }
       
    48 		    # bei einigen RRs müssen wir die Daten korrigieren
       
    49 		    when ([qw/MX A NS PTR/]) {
       
    50 			$rrset{data} .= ".$origin" unless substr($rrset{data}, -1) eq '.';
       
    51 		    }
       
    52 		}
       
    53 		my $id = sha512_hex(sort %rrset);
       
    54 		push @zone, {id => $id, rrset => \%rrset};
    35             }
    55             }
    36         }
    56         }
    37     }
    57     }
    38 
    58 
    39     return @zone;
    59     return @zone;
    40 
       
    41 }
    60 }
    42 
    61 
    43 sub nice {
    62 sub nice {
       
    63     # get a list of { id => $id, rrset => \%rrset }
    44     my @zone = 
    64     my @zone = 
    45 	sort { length $a->{label} <=> length $b->{label} or $a->{label} cmp $b->{label}}
    65 	sort { length $a->{label} <=> length $b->{label} or $a->{label}
    46 	grep { !($_->{rr} ~~ [qw(RRSIG NSEC3 NSEC3PARAM NSEC DNSKEY TSIG)]) } @_;
    66 	cmp $b->{label}} map { $_->{rrset} } @_;
    47 
    67 
       
    68     my @out;
    48     my $origin = (grep { $_->{rr} eq 'SOA' } @zone)[0]->{label};
    69     my $origin = (grep { $_->{rr} eq 'SOA' } @zone)[0]->{label};
    49     my $ttl = (grep { $_->{rr} eq 'SOA' } @zone)[0]->{ttl};
    70     my $ttl = (grep { $_->{rr} eq 'SOA' } @zone)[0]->{ttl};
    50     my $l1 = (sort map { index $_->{label}, '.' } @zone)[-1];
    71     my $l1 = (sort map { index $_->{label}, '.' } @zone)[-1];
    51     my $l2 = (sort map { length $_->{rr} } @zone)[-1];
    72     my $l2 = (sort map { length $_->{rr} } @zone)[-1];
    52     print "\$ORIGIN $origin\n";
    73     push @out, "\$ORIGIN $origin",
    53     print "\$TTL $ttl\n";
    74 	       "\$TTL $ttl";
    54 
    75 
    55     my $print = sub {
    76     my $print = sub {
    56 	my %r = %{+shift};
    77 	my %r = %{+shift};
    57 	state $last_label;;
    78 	state $last_label;;
    58 
    79 
    63 	$r{label} = do {
    84 	$r{label} = do {
    64 	    if (defined $last_label and $r{label} eq $last_label) { '' }
    85 	    if (defined $last_label and $r{label} eq $last_label) { '' }
    65 	    else { $last_label = $r{label} }
    86 	    else { $last_label = $r{label} }
    66 	};
    87 	};
    67 	
    88 	
    68 	my $rc = sprintf "%-*s %6s %-*s    %s\n",
    89 	return sprintf '%-*s %6s %-*s    %s',
    69 	    $l1 => $r{label}, $ttl, $l2 => $r{rr}, $r{data};
    90 	    $l1 => $r{label}, $ttl, $l2 => $r{rr}, $r{data};
       
    91     };
       
    92     push @out, $print->($_) foreach @zone;
       
    93     return join "\n", @out;
       
    94 }
    70 
    95 
    71 	return $rc;
    96 sub delta {
    72     };
    97     my ($zone1, $zone2) = @_;
    73     foreach (@zone) {
    98     my %zone1 = map { $_->{id}, $_->{rrset} } @$zone1;
    74 	print $print->($_);
    99     my %zone2 = map { $_->{id}, $_->{rrset} } @$zone2;
    75     }
   100     #delete @zone1{keys %zone2};
    76     return 0;
   101     #delete @zone2{keys %zone1};
       
   102     ### %zone1
       
   103     ### %zone2
       
   104     exit;
    77 }
   105 }
    78 
   106 
    79 sub main {
   107 sub main {
    80     my ($file) = @_;
   108     my ($file) = @_;
    81     my @zone = parse($file);
   109     my @zone1 = grep { 
    82     print nice(@zone);
   110 	# get { id => $id, rrset => \%rrset }
       
   111 	#not $_->{rrset}{rr} ~~ [qw(RRSIG NSEC3 NSEC3PARAM NSEC DNSKEY TSIG)]
       
   112 	$_->{rrset}{rr} ~~ [qw(SOA NS MX)]
       
   113     } parse($file);
       
   114     my $tmp = File::Temp->new();
       
   115     $tmp->print(nice @zone1);
       
   116     $tmp->close();
       
   117     system 'cat' => $tmp->filename;
       
   118     my @zone2 = parse($tmp->filename);
       
   119     delta(\@zone1, \@zone2);
    83     exit;
   120     exit;
    84     #foreach (map {$_->[1]} @zone) {
       
    85 #	next if not %{$_};
       
    86 #	next if $_->{rr} ~~ [qw(DNSKEY RRSIG NSEC3 NSECPARAM NSEC)];
       
    87 #	say $_->{data};
       
    88 #    }
       
    89 }
   121 }
    90 
   122 
    91 exit main(@ARGV) if not caller;
   123 exit main(@ARGV) if not caller;