[snapshot]
authorHeiko Schlittermann (JUMPER) <hs@schlittermann.de>
Thu, 22 May 2014 09:43:20 +0200
changeset 2 1e26b0942c13
parent 1 5f07e5c283c1
child 3 5db700038f68
[snapshot]
vidns
--- 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;