lib/DNS/Vi.pm
changeset 60 34d98030d4c0
parent 53 908e41fe9b30
child 61 bedb2cce973e
equal deleted inserted replaced
59:9a90748c1173 60:34d98030d4c0
    10 
    10 
    11 #no if $warnings::Offset{'experimental'} => (warnings => 'experimental');
    11 #no if $warnings::Offset{'experimental'} => (warnings => 'experimental');
    12 
    12 
    13 our @EXPORT    = qw(ttl2h h2ttl parse delta nice edit update show);
    13 our @EXPORT    = qw(ttl2h h2ttl parse delta nice edit update show);
    14 our @EXPORT_OK = ();
    14 our @EXPORT_OK = ();
       
    15 
       
    16 
       
    17 # the sort order for the records of the same label
       
    18 my %ORDER = map { state $n = 0; $_ => ++$n } qw(SOA NS TXT MX A AAAA SSHFP);
    15 
    19 
    16 sub parse {
    20 sub parse {
    17     my %arg   = %{ pop @_ } if ref $_[-1] eq 'HASH';
    21     my %arg   = %{ pop @_ } if ref $_[-1] eq 'HASH';
    18     my $data  = shift;
    22     my $data  = shift;
    19     my @lines = split /\n/, $data;
    23     my @lines = split /\n/, $data;
   121     }
   125     }
   122 
   126 
   123     return $out // $ttl;
   127     return $out // $ttl;
   124 }
   128 }
   125 
   129 
   126 {
   130 sub nice {
   127     my %order = map { state $n = 0; $_ => ++$n } qw(SOA NS TXT MX A AAAA SSHFP);
   131 
   128 
   132     # get a list of { id => $id, rrset => \%rrset }
   129     sub nice {
   133     # we do a schwartz transformation here
   130 
   134     # [ reverse LABEL, RRSET ]
   131         # get a list of { id => $id, rrset => \%rrset }
   135     my @zone = map { $_->[1] }
   132 	# we do a schwartz transformation here
   136 	sort {
   133 	# [ reverse LABEL, RRSET ]
   137 	    $a->[0] cmp $b->[0]
   134         my @zone = map { $_->[1] }
   138 	    or length $a->[1]{label} <=> length $b->[1]{label}
   135           sort {
   139 	    or ($ORDER{ $a->[1]{rrtype} } // 99) <=> ($ORDER{ $b->[1]{rrtype} } // 99)
   136 	      $a->[0] cmp $b->[0]
   140 	}
   137               or length $a->[1]{label} <=> length $b->[1]{label}
   141 	map { [scalar reverse($_->{label}), $_] } map { $_->{rrset} } @_;
   138               or ($order{ $a->[1]{rrtype} } // 99) <=> ($order{ $b->[1]{rrtype} } // 99)
   142 
   139           }
   143     my @out;
   140           map { [scalar reverse($_->{label}), $_] } map { $_->{rrset} } @_;
   144     my $origin = (grep { $_->{rrtype} eq 'SOA' } @zone)[0]->{label};
   141 
   145     my $ttl    = (grep { $_->{rrtype} eq 'SOA' } @zone)[0]->{ttl};
   142         my @out;
   146     my $len1 =
   143         my $origin = (grep { $_->{rrtype} eq 'SOA' } @zone)[0]->{label};
   147 	(sort { $a <=> $b } map { index $_->{label}, '.' } @zone)[-1];
   144         my $ttl    = (grep { $_->{rrtype} eq 'SOA' } @zone)[0]->{ttl};
   148     my $len2 = (sort { $a <=> $b } map { length $_->{rrtype} } @zone)[-1];
   145         my $len1 =
   149     push @out, "\$ORIGIN $origin", "\$TTL " . ttl2h($ttl);
   146           (sort { $a <=> $b } map { index $_->{label}, '.' } @zone)[-1];
   150 
   147         my $len2 = (sort { $a <=> $b } map { length $_->{rrtype} } @zone)[-1];
   151     my $print = sub {
   148         push @out, "\$ORIGIN $origin", "\$TTL " . ttl2h($ttl);
   152 	my %r = %{ +shift };
   149 
   153 	state $last_label;
   150         my $print = sub {
   154 
   151             my %r = %{ +shift };
   155 	$r{label} = '@' if $r{label} eq $origin;
   152             state $last_label;
   156 	$r{label} =~ s{\.\Q$origin\E$}{};
   153 
   157 	$r{data} =~ s{\.\Q$origin\E$}{}
   154             $r{label} = '@' if $r{label} eq $origin;
   158 	    if $r{rrtype} ~~ [qw(CNAME MX SOA PTR)];
   155             $r{label} =~ s{\.\Q$origin\E$}{};
   159 	$r{data} =~ s{\Q$origin\E$}{\@} if $r{rrtype} ~~ [qw(CNAME MX)];
   156             $r{data} =~ s{\.\Q$origin\E$}{}
   160 	$r{ttl} = $r{ttl} == $ttl ? '' : ttl2h($r{ttl});
   157               if $r{rrtype} ~~ [qw(CNAME MX SOA PTR)];
   161 	$r{label} = do {
   158             $r{data} =~ s{\Q$origin\E$}{\@} if $r{rrtype} ~~ [qw(CNAME MX)];
   162 	    if (defined $last_label and $r{label} eq $last_label) { '' }
   159             $r{ttl} = $r{ttl} == $ttl ? '' : ttl2h($r{ttl});
   163 	    else { $last_label = $r{label} }
   160             $r{label} = do {
   164 	};
   161                 if (defined $last_label and $r{label} eq $last_label) { '' }
   165 
   162                 else { $last_label = $r{label} }
   166 	return sprintf '%-*s %6s %-*s    %s',
   163             };
   167 	    $len1 => $r{label},
   164 
   168 	    $r{ttl},
   165             return sprintf '%-*s %6s %-*s    %s',
   169 	    $len2 => $r{rrtype},
   166               $len1 => $r{label},
   170 	    $r{data};
   167               $r{ttl},
   171     };
   168               $len2 => $r{rrtype},
   172     push @out, '; do NOT EDIT the SOA records SERIAL number!';
   169               $r{data};
   173     push @out, $print->($_) foreach @zone;
   170         };
   174     return join "\n", @out, '';
   171         push @out, '; do NOT EDIT the SOA records SERIAL number!';
       
   172         push @out, $print->($_) foreach @zone;
       
   173         return join "\n", @out, '';
       
   174     }
       
   175 }
   175 }
   176 
   176 
   177 sub delta {
   177 sub delta {
   178     my ($zone1, $zone2) = @_;
   178     my ($zone1, $zone2) = @_;
   179     my %zone1 = map { $_->{id}, $_->{rrset} } @$zone1;
   179     my %zone1 = map { $_->{id}, $_->{rrset} } @$zone1;