File Coverage

blib/lib/Net/DNS/RR.pm
Criterion Covered Total %
statement 291 291 100.0
branch 126 126 100.0
condition 42 42 100.0
subroutine 48 48 100.0
pod 19 21 100.0
total 526 528 100.0


line stmt bran cond sub pod time code
1             package Net::DNS::RR;
2              
3 94     94   1557 use strict;
  94         181  
  94         2755  
4 94     94   449 use warnings;
  94         164  
  94         4719  
5              
6             our $VERSION = (qw$Id: RR.pm 1910 2023-03-30 19:16:30Z willem $)[2];
7              
8              
9             =head1 NAME
10              
11             Net::DNS::RR - DNS resource record base class
12              
13             =head1 SYNOPSIS
14              
15             use Net::DNS;
16              
17             $rr = Net::DNS::RR->new('example.com IN AAAA 2001:DB8::1');
18              
19             $rr = Net::DNS::RR->new(
20             owner => 'example.com',
21             type => 'AAAA',
22             address => '2001:DB8::1'
23             );
24              
25              
26             =head1 DESCRIPTION
27              
28             Net::DNS::RR is the base class for DNS Resource Record (RR) objects.
29             See also the manual pages for each specific RR type.
30              
31             =cut
32              
33              
34 94     94   1090 use integer;
  94         188  
  94         450  
35 94     94   1904 use Carp;
  94         201  
  94         8919  
36              
37 94     94   670 use constant LIB => grep { $_ ne '.' } grep { !ref($_) } @INC;
  94         223  
  94         259  
  1128         10257  
  1128         1869  
38              
39 94     94   43206 use Net::DNS::Parameters qw(%classbyname :class :type);
  94         366  
  94         16828  
40 94     94   41695 use Net::DNS::DomainName;
  94         263  
  94         81529  
41              
42              
43             =head1 METHODS
44              
45             B Do not assume the RR objects you receive from a query
46             are of a particular type. You must always check the object type
47             before calling any of its methods. If you call an unknown method,
48             you will get an error message and execution will be terminated.
49              
50             =cut
51              
52             sub new {
53 1304     1304 1 351936 my ( $class, @list ) = @_;
54 1304         2151 my $rr = eval {
55 1304         4369 local $SIG{__DIE__};
56 1304 100       4421 scalar @list > 1 ? &_new_hash : &_new_string;
57             };
58 1304 100       5979 return $rr if $rr;
59 15 100       40 my @param = map { defined($_) ? split /\s+/ : 'undef' } @list;
  21         132  
60 15         80 my $stmnt = substr "$class->new( @param )", 0, 80;
61 15         1498 croak "${@}in $stmnt\n";
62             }
63              
64              
65             =head2 new (from string)
66              
67             $aaaa = Net::DNS::RR->new('host.example.com. 86400 AAAA 2001:DB8::1');
68             $mx = Net::DNS::RR->new('example.com. 7200 MX 10 mailhost.example.com.');
69             $cname = Net::DNS::RR->new('www.example.com 300 IN CNAME host.example.com');
70             $txt = Net::DNS::RR->new('txt.example.com 3600 HS TXT "text data"');
71              
72             Returns an object of the appropriate RR type, or a L object
73             if the type is not implemented. The attribute values are extracted from the
74             string passed by the user. The syntax of the argument string follows the
75             RFC1035 specification for zone files, and is compatible with the result
76             returned by the string method.
77              
78             The owner and RR type are required; all other information is optional.
79             Omitting the optional fields is useful for creating the empty RDATA
80             sections required for certain dynamic update operations.
81             See the L manual page for additional examples.
82              
83             All names are interpreted as fully qualified domain names.
84             The trailing dot (.) is optional.
85              
86             =cut
87              
88             my $PARSE_REGEX = q/("[^"]*")|;[^\n]*|[ \t\n\r\f()]+/; # NB: *not* \s (matches Unicode white space)
89              
90             sub _new_string {
91 994     994   1944 my ( $base, $string ) = @_;
92 994         1572 local $_ = $string;
93 994 100       2100 die 'argument absent or undefined' unless defined $_;
94 993 100       2095 die 'non-scalar argument' if ref $_;
95              
96             # parse into quoted strings, contiguous non-whitespace and (discarded) comments
97 991         2112 s/\\\\/\\092/g; # disguise escaped escape
98 991         1443 s/\\"/\\034/g; # disguise escaped quote
99 991         1451 s/\\\(/\\040/g; # disguise escaped bracket
100 991         1432 s/\\\)/\\041/g; # disguise escaped bracket
101 991         1553 s/\\;/\\059/g; # disguise escaped semicolon
102 991 100       15136 my ( $owner, @token ) = grep { defined && length } split /$PARSE_REGEX/o;
  8519         21668  
103              
104 991 100       2715 die 'unable to parse RR string' unless scalar @token;
105 990         1630 my $t1 = $token[0];
106 990         1540 my $t2 = $token[1];
107              
108 990         1783 my ( $ttl, $class );
109 990 100 100     5609 if ( not defined $t2 ) { #
    100          
    100          
110 65 100       333 @token = ('ANY') if $classbyname{uc $t1}; #
111             } elsif ( $t1 =~ /^\d/ ) {
112 234         379 $ttl = shift @token; # []
113 234 100 100     808 $class = shift @token if $classbyname{uc $t2} || $t2 =~ /^CLASS\d/i;
114             } elsif ( $classbyname{uc $t1} || $t1 =~ /^CLASS\d/i ) {
115 169         376 $class = shift @token; # []
116 169 100       604 $ttl = shift @token if $t2 =~ /^\d/;
117             }
118              
119 990         1765 my $type = shift(@token);
120 990         1467 my $populated = scalar @token;
121              
122 990         2422 my $self = $base->_subclass( $type, $populated ); # create RR object
123 989         2915 $self->owner($owner);
124 989         2368 &class( $self, $class ); # specify CLASS
125 989         2443 &ttl( $self, $ttl ); # specify TTL
126              
127 989 100       2204 return $self unless $populated; # empty RR
128              
129 897 100 100     3311 if ( $#token && $token[0] =~ /^[\\]?#$/ ) {
130 28         53 shift @token; # RFC3597 hexadecimal format
131 28   100     75 my $rdlen = shift(@token) || 0;
132 28         148 my $rdata = pack 'H*', join( '', @token );
133 28 100       120 die 'length and hexadecimal data inconsistent' unless $rdlen == length $rdata;
134 25         63 $self->rdata($rdata); # unpack RDATA
135             } else {
136 869         2384 $self->_parse_rdata(@token); # parse arguments
137             }
138              
139 873         2555 $self->_post_parse();
140 869         3217 return $self;
141             }
142              
143              
144             =head2 new (from hash)
145              
146             $rr = Net::DNS::RR->new(%hash);
147              
148             $rr = Net::DNS::RR->new(
149             owner => 'host.example.com',
150             ttl => 86400,
151             class => 'IN',
152             type => 'AAAA',
153             address => '2001:DB8::1'
154             );
155            
156             $rr = Net::DNS::RR->new(
157             owner => 'txt.example.com',
158             type => 'TXT',
159             txtdata => [ 'one', 'two' ]
160             );
161              
162             Returns an object of the appropriate RR type, or a L object
163             if the type is not implemented. Consult the relevant manual pages for the
164             usage of type specific attributes.
165              
166             The owner and RR type are required; all other information is optional.
167             Omitting optional attributes is useful for creating the empty RDATA
168             sections required for certain dynamic update operations.
169              
170             =cut
171              
172             my @core = qw(owner name type class ttl rdlength);
173              
174             sub _new_hash {
175 597     597   1161 my $base = shift;
176              
177 597         2062 my %attribute = ( owner => '.', type => 'NULL' );
178 597         1769 while ( my $key = shift ) {
179 1374         3838 $attribute{lc $key} = shift;
180             }
181              
182 597         2864 my ( $owner, $name, $type, $class, $ttl ) = delete @attribute{@core};
183              
184 597         2297 my $self = $base->_subclass( $type, scalar(%attribute) );
185 597 100       2742 $self->owner( $name ? $name : $owner );
186 597 100       1551 $self->class($class) if defined $class; # optional CLASS
187 597 100       1421 $self->ttl($ttl) if defined $ttl; # optional TTL
188              
189 597         1046 eval {
190 597         2352 while ( my ( $attribute, $value ) = each %attribute ) {
191 466 100       1948 $self->$attribute( ref($value) eq 'ARRAY' ? @$value : $value );
192             }
193             };
194 597 100       1748 die ref($self) eq __PACKAGE__ ? "type $type not implemented" : () if $@;
    100          
195              
196 595         2130 $self->_post_parse();
197 595         2933 return $self;
198             }
199              
200              
201             =head2 decode
202              
203             ( $rr, $next ) = Net::DNS::RR->decode( \$data, $offset, @opaque );
204              
205             Decodes a DNS resource record at the specified location within a
206             DNS packet.
207              
208             The argument list consists of a reference to the buffer containing
209             the packet data and offset indicating where resource record begins.
210             Any remaining arguments are passed as opaque data to subordinate
211             decoders and do not form part of the published interface.
212              
213             Returns a C object and the offset of the next record
214             in the packet.
215              
216             An exception is raised if the data buffer contains insufficient or
217             corrupt data.
218              
219             =cut
220              
221 94     94   822 use constant RRFIXEDSZ => length pack 'n2 N n', (0) x 4;
  94         207  
  94         304168  
222              
223             sub decode {
224 9812     9812 1 22488 my ( $base, @argument ) = @_;
225              
226 9812         22890 my ( $owner, $fixed ) = Net::DNS::DomainName1035->decode(@argument);
227 9811         15660 my $index = $fixed + RRFIXEDSZ;
228 9811         18091 my ( $data, $offset, @opaque ) = @argument;
229 9811 100       19266 die 'corrupt wire-format data' if length $$data < $index;
230 9810         28457 my $self = $base->_subclass( unpack "\@$fixed n", $$data );
231 9810         17989 $self->{owner} = $owner;
232 9810         25046 @{$self}{qw(class ttl rdlength)} = unpack "\@$fixed x2 n N n", $$data;
  9810         24865  
233              
234 9810         15795 my $next = $index + $self->{rdlength};
235 9810 100       19891 die 'corrupt wire-format data' if length $$data < $next;
236              
237 9809         19569 local $self->{offset} = $offset;
238 9809 100 100     35856 $self->_decode_rdata( $data, $index, @opaque ) if $next > $index or $self->type eq 'OPT';
239              
240 9803 100       34106 return wantarray ? ( $self, $next ) : $self;
241             }
242              
243              
244             =head2 encode
245              
246             $data = $rr->encode( $offset, @opaque );
247              
248             Returns the C in binary format suitable for inclusion
249             in a DNS packet buffer.
250              
251             The offset indicates the intended location within the packet data
252             where the C is to be stored.
253              
254             Any remaining arguments are opaque data which are passed intact to
255             subordinate encoders.
256              
257             =cut
258              
259             sub encode {
260 1112     1112 1 31630 my ( $self, $offset, @opaque ) = @_;
261 1112 100       2449 ( $offset, @opaque ) = ( 0x4000, {} ) unless defined $offset;
262              
263 1112         2754 my $owner = $self->{owner}->encode( $offset, @opaque );
264 1112         1741 my ( $type, $class, $ttl ) = @{$self}{qw(type class ttl)};
  1112         2388  
265 1112 100       2378 my $rdata = $self->_empty ? '' : $self->_encode_rdata( $offset + length($owner) + RRFIXEDSZ, @opaque );
266 1112   100     8488 return pack 'a* n2 N n a*', $owner, $type, $class || 1, $ttl || 0, length $rdata, $rdata;
      100        
267             }
268              
269              
270             =head2 canonical
271              
272             $data = $rr->canonical;
273              
274             Returns the C in canonical binary format suitable for
275             DNSSEC signature validation.
276              
277             The absence of the associative array argument signals to subordinate
278             encoders that the canonical uncompressed lower case form of embedded
279             domain names is to be used.
280              
281             =cut
282              
283             sub canonical {
284 305     305 1 474 my $self = shift;
285              
286 305         667 my $owner = $self->{owner}->canonical;
287 305         494 my ( $type, $class, $ttl ) = @{$self}{qw(type class ttl)};
  305         631  
288 305 100       563 my $rdata = $self->_empty ? '' : $self->_encode_rdata( length($owner) + RRFIXEDSZ );
289 305   100     2252 return pack 'a* n2 N n a*', $owner, $type, $class || 1, $ttl || 0, length $rdata, $rdata;
      100        
290             }
291              
292              
293             =head2 print
294              
295             $rr->print;
296              
297             Prints the resource record to the currently selected output filehandle.
298             Calls the string method to get the formatted RR representation.
299              
300             =cut
301              
302             sub print {
303 25     25 1 948 print shift->string, "\n";
304 25         651 return;
305             }
306              
307              
308             =head2 string
309              
310             print $rr->string, "\n";
311              
312             Returns a string representation of the RR using the master file format
313             mandated by RFC1035.
314             All domain names are fully qualified with trailing dot.
315             This differs from RR attribute methods, which omit the trailing dot.
316              
317             =cut
318              
319             sub string {
320 1159     1159 1 3704 my $self = shift;
321              
322 1159         3811 my $name = $self->{owner}->string;
323 1159         2704 my @ttl = grep {defined} $self->{ttl};
  1159         3131  
324 1159         2886 my @core = ( $name, @ttl, $self->class, $self->type );
325              
326 1159         3317 local $SIG{__DIE__};
327 1159         2347 my $empty = $self->_empty;
328 1159 100       2670 my @rdata = $empty ? () : eval { $self->_format_rdata };
  1125         2749  
329 1159 100       3058 carp $@ if $@;
330              
331 1159 100       2538 my $tab = length($name) < 72 ? "\t" : ' ';
332 1159         3825 my @line = _wrap( join( $tab, @core, '(' ), @rdata, ')' );
333              
334 1159         2238 my $last = pop(@line); # last or only line
335 1159 100       2538 $last = join $tab, @core, "@rdata" unless scalar(@line);
336              
337 1159 100       2235 $self->_annotation('no data') if $empty;
338 1159         2859 return join "\n\t", @line, _wrap( $last, map {"; $_"} $self->_annotation );
  66         258  
339             }
340              
341              
342             =head2 plain
343              
344             $plain = $rr->plain;
345              
346             Returns a simplified single-line representation of the RR.
347             This facilitates interaction with programs like nsupdate
348             which have rudimentary parsers.
349              
350             =cut
351              
352             sub plain {
353 8     8 1 89 return join ' ', shift->token;
354             }
355              
356              
357             =head2 token
358              
359             @token = $rr->token;
360              
361             Returns a token list representation of the RR zone file string.
362              
363             =cut
364              
365             sub token {
366 7     7 1 14 my $self = shift;
367              
368 7         16 my @ttl = grep {defined} $self->{ttl};
  7         23  
369 7         19 my @core = ( $self->{owner}->string, @ttl, $self->class, $self->type );
370              
371             # parse into quoted strings, contiguous non-whitespace and (discarded) comments
372 7 100       19 local $_ = $self->_empty ? '' : join( ' ', $self->_format_rdata );
373 7         17 s/\\\\/\\092/g; # disguise escaped escape
374 7         10 s/\\"/\\034/g; # disguise escaped quote
375 7         12 s/\\\(/\\040/g; # disguise escaped bracket
376 7         9 s/\\\)/\\041/g; # disguise escaped bracket
377 7         10 s/\\;/\\059/g; # disguise escaped semicolon
378 7 100       94 return ( @core, grep { defined && length } split /$PARSE_REGEX/o );
  35         107  
379             }
380              
381              
382             =head2 generic
383              
384             $generic = $rr->generic;
385              
386             Returns the generic RR representation defined in RFC3597. This facilitates
387             creation of zone files containing RRs unrecognised by outdated nameservers
388             and provisioning software.
389              
390             =cut
391              
392             sub generic {
393 8     8 1 16 my $self = shift;
394              
395 8         20 my @ttl = grep {defined} $self->{ttl};
  8         25  
396 8         17 my @class = map {"CLASS$_"} grep {defined} $self->{class};
  3         13  
  8         20  
397 8         34 my @core = ( $self->{owner}->string, @ttl, @class, "TYPE$self->{type}" );
398 8         22 my $data = $self->rdata;
399 8         55 my @data = ( '\\#', length($data), split /(\S{32})/, unpack 'H*', $data );
400 8         35 my @line = _wrap( "@core (", @data, ')' );
401 8 100       32 return join "\n\t", @line if scalar(@line) > 1;
402 7         39 return join ' ', @core, @data;
403             }
404              
405              
406             =head2 owner name
407              
408             $name = $rr->owner;
409              
410             Returns the owner name of the record.
411              
412             =cut
413              
414             sub owner {
415 4268     4268 1 8321 my ( $self, @name ) = @_;
416 4268         7236 for (@name) { $self->{owner} = Net::DNS::DomainName1035->new($_) }
  1586         6069  
417 4268 100       10259 return defined wantarray ? $self->{owner}->name : undef;
418             }
419              
420 439     439 1 7048 sub name { return &owner; } ## historical
421              
422              
423             =head2 type
424              
425             $type = $rr->type;
426              
427             Returns the record type.
428              
429             =cut
430              
431             sub type {
432 2468     2468 1 4737 my ( $self, @value ) = @_;
433 2468         4459 for (@value) { croak 'not possible to change RR->type' }
  1         72  
434 2467         5835 return typebyval( $self->{type} );
435             }
436              
437              
438             =head2 class
439              
440             $class = $rr->class;
441              
442             Resource record class.
443              
444             =cut
445              
446             sub class {
447 2797     2797 1 6548 my ( $self, $class ) = @_;
448 2797 100       6093 return $self->{class} = classbyname($class) if defined $class;
449 1981 100       5660 return defined $self->{class} ? classbyval( $self->{class} ) : 'IN';
450             }
451              
452              
453             =head2 ttl
454              
455             $ttl = $rr->ttl;
456             $ttl = $rr->ttl(3600);
457              
458             Resource record time to live in seconds.
459              
460             =cut
461              
462             # The following time units are recognised, but are not part of the
463             # published API. These are required for parsing BIND zone files but
464             # should not be used in other contexts.
465             my %unit = ( W => 604800, D => 86400, H => 3600, M => 60, S => 1 );
466              
467             sub ttl {
468 1447     1447 1 3715 my ( $self, $time ) = @_;
469              
470 1447 100 100     3734 return $self->{ttl} || 0 unless defined $time; # avoid defining rr->{ttl}
471              
472 633         818 my $ttl = 0;
473 633         3174 my %time = reverse split /(\D)\D*/, $time . 'S';
474 633         2250 while ( my ( $u, $t ) = each %time ) {
475 633   100     1532 my $scale = $unit{uc $u} || die qq(bad time: $t$u);
476 632         2075 $ttl += $t * $scale;
477             }
478 632         1957 return $self->{ttl} = $ttl;
479             }
480              
481              
482             ################################################################################
483             ##
484             ## Default implementation for unknown RR type
485             ##
486             ################################################################################
487              
488             sub _decode_rdata { ## decode rdata from wire-format octet string
489 3     3   7 my ( $self, $data, $offset ) = @_;
490 3         9 return $self->{rdata} = substr $$data, $offset, $self->{rdlength};
491             }
492              
493              
494             sub _encode_rdata { ## encode rdata as wire-format octet string
495 6     6   15 return shift->{rdata};
496             }
497              
498              
499             sub _format_rdata { ## format rdata portion of RR string
500 7     7   17 my $rdata = shift->rdata; # RFC3597 unknown RR format
501 7         46 return ( '\\#', length($rdata), split /(\S{32})/, unpack 'H*', $rdata );
502             }
503              
504              
505             sub _parse_rdata { ## parse RR attributes in argument list
506 2     2   4 my $self = shift;
507 2 100       10 die join ' ', 'type', $self->type, 'not implemented' if ref($self) eq __PACKAGE__;
508 1         6 die join ' ', 'no zone file representation defined for', $self->type;
509             }
510              
511              
512       1438     sub _post_parse { } ## parser post processing
513              
514              
515       114     sub _defaults { } ## set attribute default values
516              
517              
518             sub dump { ## print internal data structure
519 2     2 0 152 my @data = @_; # uncoverable pod
520 2         12 require Data::Dumper;
521 2   100     9 local $Data::Dumper::Maxdepth = $Data::Dumper::Maxdepth || 6;
522 2   100     6 local $Data::Dumper::Sortkeys = $Data::Dumper::Sortkeys || 1;
523 2   100     17 local $Data::Dumper::Useqq = $Data::Dumper::Useqq || 1;
524 2         5 return print Data::Dumper::Dumper(@data);
525             }
526              
527             sub rdatastr { ## historical RR subtype method
528 2     2 0 3 my $self = shift; # uncoverable pod
529 2         10 $self->_deprecate('prefer $rr->rdstring()');
530 2         8 return $self->rdstring;
531             }
532              
533              
534             =head2 rdata
535              
536             $rr = Net::DNS::RR->new( type => NULL, rdata => 'arbitrary' );
537              
538             Resource record data section when viewed as opaque octets.
539              
540             =cut
541              
542             sub rdata {
543 167     167 1 1988 my $self = shift;
544              
545 167 100       743 return $self->_empty ? '' : eval { $self->_encode_rdata( 0x4000, {} ) } unless @_;
  117 100       453  
546              
547 30   100     72 my $data = shift || '';
548 30 100       136 $self->_decode_rdata( \$data, 0 ) if ( $self->{rdlength} = length $data );
549 28         73 return;
550             }
551              
552              
553             =head2 rdstring
554              
555             $rdstring = $rr->rdstring;
556              
557             Returns a string representation of the RR-specific data.
558              
559             =cut
560              
561             sub rdstring {
562 88     88 1 3562 my $self = shift;
563 88         267 local $SIG{__DIE__};
564              
565 88 100       213 my @rdata = $self->_empty ? () : eval { $self->_format_rdata };
  69         201  
566 88 100       328 carp $@ if $@;
567              
568 88         222 return join "\n\t", _wrap(@rdata);
569             }
570              
571              
572             =head2 rdlength
573              
574             $rdlength = $rr->rdlength;
575              
576             Returns the uncompressed length of the encoded RR-specific data.
577              
578             =cut
579              
580             sub rdlength {
581 7     7 1 78 return length shift->rdata;
582             }
583              
584              
585             ###################################################################################
586              
587             =head1 Sorting of RR arrays
588              
589             Sorting of RR arrays is done by Net::DNS::rrsort(), see documentation
590             for L. This package provides class methods to set the
591             comparator function used for a particular RR based on its attributes.
592              
593              
594             =head2 set_rrsort_func
595              
596             my $function = sub { ## numerically ascending order
597             $Net::DNS::a->{'preference'} <=> $Net::DNS::b->{'preference'};
598             };
599              
600             Net::DNS::RR::MX->set_rrsort_func( 'preference', $function );
601              
602             Net::DNS::RR::MX->set_rrsort_func( 'default_sort', $function );
603              
604             set_rrsort_func() must be called as a class method. The first argument is
605             the attribute name on which the sorting is to take place. If you specify
606             "default_sort" then that is the sort algorithm that will be used when
607             get_rrsort_func() is called without an RR attribute as argument.
608              
609             The second argument is a reference to a comparator function that uses the
610             global variables $a and $b in the Net::DNS package. During sorting, the
611             variables $a and $b will contain references to objects of the class whose
612             set_rrsort_func() was called. The above sorting function will only be
613             applied to Net::DNS::RR::MX objects.
614              
615             The above example is the sorting function implemented in MX.
616              
617             =cut
618              
619             our %rrsortfunct;
620              
621             sub set_rrsort_func {
622 42     42 1 115 my $class = shift;
623 42         80 my $attribute = shift;
624 42         70 my $function = shift;
625              
626 42         311 my ($type) = $class =~ m/::([^:]+)$/;
627 42         153 $rrsortfunct{$type}{$attribute} = $function;
628 42         109 return;
629             }
630              
631              
632             =head2 get_rrsort_func
633              
634             $function = Net::DNS::RR::MX->get_rrsort_func('preference');
635             $function = Net::DNS::RR::MX->get_rrsort_func();
636              
637             get_rrsort_func() returns a reference to the comparator function.
638              
639             =cut
640              
641             my $default = sub { return $Net::DNS::a->canonical() cmp $Net::DNS::b->canonical(); };
642              
643             sub get_rrsort_func {
644 13     13 1 1615 my $class = shift;
645 13   100     40 my $attribute = shift || 'default_sort';
646              
647 13         84 my ($type) = $class =~ m/::([^:]+)$/;
648              
649 13   100     58 return $rrsortfunct{$type}{$attribute} || return $default;
650             }
651              
652              
653             ################################################################################
654             #
655             # Net::DNS::RR->_subclass($rrname)
656             # Net::DNS::RR->_subclass($rrname, $default)
657             #
658             # Create a new object blessed into appropriate RR subclass, after
659             # loading the subclass module (if necessary). A subclass with no
660             # corresponding module will be regarded as unknown and blessed
661             # into the RR base class.
662             #
663             # The optional second argument indicates that default values are
664             # to be copied into the newly created object.
665              
666             our %_MINIMAL = ( 255 => bless ['type' => 255], __PACKAGE__ );
667             our %_LOADED = %_MINIMAL;
668              
669             sub _subclass {
670 11397     11397   20719 my ( $class, $rrname, $default ) = @_;
671              
672 11397 100       25441 unless ( $_LOADED{$rrname} ) {
673 180         876 my $rrtype = typebyname($rrname);
674              
675 179 100       616 unless ( $_LOADED{$rrtype} ) { # load once only
676 170         963 local @INC = LIB;
677              
678 170         560 my $identifier = typebyval($rrtype);
679 170         655 $identifier =~ s/\W/_/g; # kosher Perl identifier
680              
681 170         625 my $subclass = join '::', __PACKAGE__, $identifier;
682              
683 170 100       11616 unless ( eval "require $subclass" ) { ## no critic ProhibitStringyEval
684 1         9 my $perl = Net::DNS::Parameters::_typespec("$rrtype.RRTYPE");
685 1         5 $subclass = join '::', __PACKAGE__, "TYPE$rrtype";
686             push @INC, sub { # see perldoc -f require
687 1     1   7 my @line = split /\n/, $perl;
688 1         63 return ( sub { defined( $_ = shift @line ) } );
  1         35  
689 1         8 };
690 1         51 eval "require $subclass"; ## no critic ProhibitStringyEval
691             }
692              
693 170 100       897 $subclass = __PACKAGE__ if $@;
694              
695             # cache pre-built minimal and populated default object images
696 170         712 my @base = ( 'type' => $rrtype );
697 170         951 $_MINIMAL{$rrtype} = bless [@base], $subclass;
698              
699 170         647 my $object = bless {@base}, $subclass;
700 170         1249 $object->_defaults;
701 170         2120 $_LOADED{$rrtype} = bless [%$object], $subclass;
702             }
703              
704 179         643 $_MINIMAL{$rrname} = $_MINIMAL{$rrtype};
705 179         513 $_LOADED{$rrname} = $_LOADED{$rrtype};
706             }
707              
708 11396 100       21200 my $prebuilt = $default ? $_LOADED{$rrname} : $_MINIMAL{$rrname};
709 11396         43144 return bless {@$prebuilt}, ref($prebuilt); # create object
710             }
711              
712              
713             sub _annotation {
714 1227     1227   7635 my ( $self, @note ) = @_;
715 1227 100       2416 $self->{annotation} = ["@note"] if scalar @note;
716 1227 100       2273 return wantarray ? @{$self->{annotation} || []} : ();
  1159 100       5217  
717             }
718              
719              
720             my %warned;
721              
722             sub _deprecate {
723 9     9   22 my ( undef, @note ) = @_;
724 9 100       682 carp "deprecated method; @note" unless $warned{"@note"}++;
725 9         264 return;
726             }
727              
728              
729             my %ignore = map { ( $_ => 1 ) } @core, 'annotation', '#';
730              
731             sub _empty {
732 2808     2808   3898 my $self = shift;
733 2808   100     11593 return not( $self->{'#'} ||= scalar grep { !$ignore{$_} } keys %$self );
  8186         18083  
734             }
735              
736              
737             sub _wrap {
738 2435     2435   5472 my @text = @_;
739 2435         3106 my $cols = 80;
740 2435         2803 my $coln = 0;
741              
742 2435         3190 my ( @line, @fill );
743 2435         3956 foreach (@text) {
744 5665   100     10202 $coln += ( length || next ) + 1;
745 5627 100       8783 if ( $coln > $cols ) { # start new line
746 1763 100       4075 push( @line, join ' ', @fill ) if @fill;
747 1763         2437 $coln = length;
748 1763         2406 @fill = ();
749             }
750 5627 100       9508 $coln = $cols if chomp; # force line break
751 5627 100       11301 push( @fill, $_ ) if length;
752             }
753 2435         14047 return ( @line, join ' ', @fill );
754             }
755              
756              
757             ################################################################################
758              
759       1     sub DESTROY { } ## Avoid tickling AUTOLOAD (in cleanup)
760              
761             ## no critic
762             sub AUTOLOAD { ## Default method
763 10     10   588 my ($self) = @_;
764              
765 94     94   892 no strict 'refs'; ## no critic ProhibitNoStrict
  94         255  
  94         33845  
766 10         16 our $AUTOLOAD;
767 10         49 my ($method) = reverse split /::/, $AUTOLOAD;
768              
769 10         36 for ( my $action = $method ) { ## tolerate mixed-case attribute name
770 10         27 tr [A-Z-] [a-z_];
771 10 100       70 if ( $self->can($action) ) {
772 7     19   66 *{$AUTOLOAD} = sub { shift->$action(@_) };
  7         48  
  19         2116  
773 7         42 return &$AUTOLOAD;
774             }
775             }
776              
777 3         8 my $oref = ref($self);
778 3     1   9 *{$AUTOLOAD} = sub {}; ## suppress deep recursion
  3         31  
779 3 100       207 croak qq[$self has no class method "$method"] unless $oref;
780              
781 2         8 my $string = $self->string;
782 2         25 my @object = grep { defined($_) } $oref, $oref->VERSION;
  4         12  
783 2         8 my $module = join '::', __PACKAGE__, $self->type;
784 2 100       79 eval("require $module") if $oref eq __PACKAGE__; ## no critic ProhibitStringyEval
785              
786 2         18 @_ = ( <<"END" );
787             *** FATAL PROGRAM ERROR!! Unknown instance method "$method"
788             *** which the program has attempted to call for the object:
789             ***
790             $string
791             ***
792             *** THIS IS A BUG IN THE CALLING SOFTWARE, which incorrectly assumes
793             *** that the object would be of a particular type. The type of an
794             *** object should be checked before calling any of its methods.
795             ***
796             @object
797             $@
798             END
799 2         532 goto &Carp::confess;
800             }
801              
802              
803             1;
804             __END__