File Coverage

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


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