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