--- a/vidns Tue May 20 23:23:41 2014 +0200
+++ b/vidns Thu May 22 09:43:20 2014 +0200
@@ -4,6 +4,7 @@
use warnings;
use File::Temp;
use Smart::Comments;
+use Digest::SHA qw(sha512_hex);
sub parse {
my $file = shift;
@@ -14,43 +15,63 @@
};
my @zone;
+ my ($origin, $ttl, $last_label);
foreach (@lines) {
+ s{;.*$}{};
given ($_) {
- when (m{^;}) { next }
+ when (m{^\s*\$ORIGIN\s+(\S+)}) { $origin = $1 }
+ when (m{^\s*\$TTL\s+(\S+)}) { $ttl = $1 }
when (
- m{^(?<label>\S+)
+ m{^(?<label>\S+)?
\s+(?<ttl>\S+(?=\s+))
\s+(?:(?:IN|ANY)\s+)?(?<rr>\S+(?=\s+))
\s+(?<data>.*)
}x
)
{
- push @zone, {
- label => $+{label},
- ttl => $+{ttl},
+ my %rrset = (
+ label => $last_label = defined $+{label}
+ ? $+{label} eq '@' ? $origin : $+{label}
+ : $last_label,
+ ttl => $+{ttl} // $ttl,
rr => uc $+{rr},
data => $+{data},
- };
+ );
+
+ # label ergänzen, wenn nicht FQDN
+ $rrset{label} .= ".$origin" unless substr($rrset{label}, -1) eq '.';
+
+ given ($rrset{rr}) {
+ # origin steht im SOA
+ when('SOA') { $origin = $rrset{label} }
+ # bei einigen RRs müssen wir die Daten korrigieren
+ when ([qw/MX A NS PTR/]) {
+ $rrset{data} .= ".$origin" unless substr($rrset{data}, -1) eq '.';
+ }
+ }
+ my $id = sha512_hex(sort %rrset);
+ push @zone, {id => $id, rrset => \%rrset};
}
}
}
return @zone;
-
}
sub nice {
+ # get a list of { id => $id, rrset => \%rrset }
my @zone =
- sort { length $a->{label} <=> length $b->{label} or $a->{label} cmp $b->{label}}
- grep { !($_->{rr} ~~ [qw(RRSIG NSEC3 NSEC3PARAM NSEC DNSKEY TSIG)]) } @_;
+ sort { length $a->{label} <=> length $b->{label} or $a->{label}
+ cmp $b->{label}} map { $_->{rrset} } @_;
+ my @out;
my $origin = (grep { $_->{rr} eq 'SOA' } @zone)[0]->{label};
my $ttl = (grep { $_->{rr} eq 'SOA' } @zone)[0]->{ttl};
my $l1 = (sort map { index $_->{label}, '.' } @zone)[-1];
my $l2 = (sort map { length $_->{rr} } @zone)[-1];
- print "\$ORIGIN $origin\n";
- print "\$TTL $ttl\n";
+ push @out, "\$ORIGIN $origin",
+ "\$TTL $ttl";
my $print = sub {
my %r = %{+shift};
@@ -65,27 +86,38 @@
else { $last_label = $r{label} }
};
- my $rc = sprintf "%-*s %6s %-*s %s\n",
+ return sprintf '%-*s %6s %-*s %s',
$l1 => $r{label}, $ttl, $l2 => $r{rr}, $r{data};
-
- return $rc;
};
- foreach (@zone) {
- print $print->($_);
- }
- return 0;
+ push @out, $print->($_) foreach @zone;
+ return join "\n", @out;
+}
+
+sub delta {
+ my ($zone1, $zone2) = @_;
+ my %zone1 = map { $_->{id}, $_->{rrset} } @$zone1;
+ my %zone2 = map { $_->{id}, $_->{rrset} } @$zone2;
+ #delete @zone1{keys %zone2};
+ #delete @zone2{keys %zone1};
+ ### %zone1
+ ### %zone2
+ exit;
}
sub main {
my ($file) = @_;
- my @zone = parse($file);
- print nice(@zone);
+ my @zone1 = grep {
+ # get { id => $id, rrset => \%rrset }
+ #not $_->{rrset}{rr} ~~ [qw(RRSIG NSEC3 NSEC3PARAM NSEC DNSKEY TSIG)]
+ $_->{rrset}{rr} ~~ [qw(SOA NS MX)]
+ } parse($file);
+ my $tmp = File::Temp->new();
+ $tmp->print(nice @zone1);
+ $tmp->close();
+ system 'cat' => $tmp->filename;
+ my @zone2 = parse($tmp->filename);
+ delta(\@zone1, \@zone2);
exit;
- #foreach (map {$_->[1]} @zone) {
-# next if not %{$_};
-# next if $_->{rr} ~~ [qw(DNSKEY RRSIG NSEC3 NSECPARAM NSEC)];
-# say $_->{data};
-# }
}
exit main(@ARGV) if not caller;