File Coverage

blib/lib/Net/DNS/RR/APL.pm
Criterion Covered Total %
statement 96 96 100.0
branch 20 20 100.0
path n/a
condition 12 12 100.0
subroutine 17 17 100.0
pod 1 1 100.0
total 146 146 100.0


line stmt bran path cond sub pod time code
1               package Net::DNS::RR::APL;
2                
3 2       2   12 use strict;
  2           4  
  2           60  
4 2       2   6 use warnings;
  2           3  
  2           141  
5               our $VERSION = (qw$Id: APL.pm 2003 2025-01-21 12:06:06Z willem $)[2];
6                
7 2       2   10 use base qw(Net::DNS::RR);
  2           4  
  2           181  
8                
9                
10               =head1 NAME
11                
12               Net::DNS::RR::APL - DNS APL resource record
13                
14               =cut
15                
16 2       2   11 use integer;
  2           3  
  2           29  
17                
18 2       2   49 use Carp;
  2           3  
  2           1378  
19                
20                
21               sub _decode_rdata { ## decode rdata from wire-format octet string
22 5       5   11 my ( $self, $data, $offset ) = @_;
23                
24 5           12 my $limit = $offset + $self->{rdlength};
25                
26 5           11 my $aplist = $self->{aplist} = [];
27 5           46 while ( $offset < $limit ) {
28 25           44 my $xlen = unpack "\@$offset x3 C", $$data;
29 25           32 my $size = ( $xlen & 0x7F );
30 25           38 my $item = bless {}, 'Net::DNS::RR::APL::Item';
31 25           40 $item->{negate} = $xlen - $size;
32 25           54 @{$item}{qw(family prefix address)} = unpack "\@$offset n C x a$size", $$data;
  25           43  
33 25           33 $offset += $size + 4;
34 25           42 push @$aplist, $item;
35               }
36 5 100         182 croak('corrupt APL data') unless $offset == $limit; # more or less FUBAR
37 4           11 return;
38               }
39                
40                
41               sub _encode_rdata { ## encode rdata as wire-format octet string
42 7       7   7 my $self = shift;
43                
44 7           7 my @rdata;
45 7           8 my $aplist = $self->{aplist};
46 7           10 foreach (@$aplist) {
47 27           27 my $address = $_->{address};
48 27           36 $address =~ s/[\000]+$//; # strip trailing null octets
49 27 100         36 my $xlength = ( $_->{negate} ? 0x80 : 0 ) | length($address);
50 27           24 push @rdata, pack 'n C2 a*', @{$_}{qw(family prefix)}, $xlength, $address;
  27           51  
51               }
52 7           22 return join '', @rdata;
53               }
54                
55                
56               sub _format_rdata { ## format rdata portion of RR string.
57 2       2   2 my $self = shift;
58                
59 2           3 my $aplist = $self->{aplist};
60 2           3 my @rdata = map { $_->string } @$aplist;
  2           3  
61 2           5 return @rdata;
62               }
63                
64                
65               sub _parse_rdata { ## populate RR from rdata in argument list
66 4       4   8 my ( $self, @argument ) = @_;
67                
68 4           8 $self->aplist(@argument);
69 3           5 return;
70               }
71                
72                
73               sub aplist {
74 20       20 1 38 my ( $self, @argument ) = @_;
75                
76 20           28 while ( scalar @argument ) { # parse apitem strings
77 26 100         51 last unless $argument[0] =~ m#[!:./]#;
78 13           17 local $_ = shift @argument;
79 13           38 m#^(!?)(\d+):(.+)/(\d+)$#;
80 13 100         28 my $n = $1 ? 1 : 0;
81 13     100     25 my $f = $2 || 0;
82 13           17 my $a = $3;
83 13     100     31 my $p = $4 || 0;
84 13           39 $self->aplist( negate => $n, family => $f, address => $a, prefix => $p );
85               }
86                
87 19     100     31 my $aplist = $self->{aplist} ||= [];
88 19 100         48 if ( my %argval = @argument ) { # parse attribute=value list
89 13           18 my $item = bless {}, 'Net::DNS::RR::APL::Item';
90 13           26 while ( my ( $attribute, $value ) = each %argval ) {
91 52 100         98 $item->$attribute($value) unless $attribute eq 'address';
92               }
93 13           24 $item->address( $argval{address} ); # address must be last
94 12           17 push @$aplist, $item;
95               }
96                
97 18           24 my @ap = @$aplist;
98 18 100         59 return unless defined wantarray;
99 2 100         6 return wantarray ? @ap : join ' ', map { $_->string } @ap;
  1           2  
100               }
101                
102                
103               ########################################
104                
105                
106               package Net::DNS::RR::APL::Item; ## no critic ProhibitMultiplePackages
107                
108 2       2   522 use Net::DNS::RR::A;
  2           4  
  2           44  
109 2       2   419 use Net::DNS::RR::AAAA;
  2           3  
  2           715  
110                
111               my %family = qw(1 Net::DNS::RR::A 2 Net::DNS::RR::AAAA);
112                
113                
114               sub negate {
115 18       18   1145 my ( $self, @value ) = @_;
116 18           22 for (@value) { return $self->{negate} = $_ }
  13           37  
117 5           15 return $self->{negate};
118               }
119                
120                
121               sub family {
122 52       52   1076 my ( $self, @value ) = @_;
123 52           55 for (@value) { $self->{family} = 0 + $_ }
  13           18  
124 52     100     144 return $self->{family} || 0;
125               }
126                
127                
128               sub prefix {
129 33       33   40 my ( $self, @value ) = @_;
130 33           36 for (@value) { $self->{prefix} = 0 + $_ }
  13           17  
131 33     100     86 return $self->{prefix} || 0;
132               }
133                
134                
135               sub address {
136 26       26   996 my ( $self, @value ) = @_;
137                
138 26     100     54 my $family = $family{$self->family} || die 'unknown address family';
139 25 100         78 return bless( {%$self}, $family )->address unless scalar @value;
140                
141 12           14 my $bitmask = $self->prefix;
142 12           30 my $address = bless( {}, $family )->address( shift @value );
143 12           61 return $self->{address} = pack "B$bitmask", unpack 'B*', $address;
144               }
145                
146                
147               sub string {
148 8       8   876 my $self = shift;
149                
150 8 100         27 my $not = $self->{negate} ? '!' : '';
151 8           14 my ( $family, $address, $prefix ) = ( $self->family, $self->address, $self->prefix );
152 8           41 return "$not$family:$address/$prefix";
153               }
154                
155                
156               1;
157               __END__