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