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   1691 use strict;
  94         185  
  94         2843  
4 94     94   457 use warnings;
  94         196  
  94         4971  
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   1105 use integer;
  94         199  
  94         490  
35 94     94   1914 use Carp;
  94         226  
  94         9259  
36              
37 94     94   713 use constant LIB => grep { $_ ne '.' } grep { !ref($_) } @INC;
  94         213  
  94         288  
  1128         11134  
  1128         1914  
38              
39 94     94   45541 use Net::DNS::Parameters qw(%classbyname :class :type);
  94         381  
  94         18252  
40 94     94   43690 use Net::DNS::DomainName;
  94         296  
  94         83554  
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 1301     1301 1 384339 my ( $class, @list ) = @_;
54 1301         2333 my $rr = eval {
55 1301         4400 local $SIG{__DIE__};
56 1301 100       4677 scalar @list > 1 ? &_new_hash : &_new_string;
57             };
58 1301 100       6283 return $rr if $rr;
59 15 100       36 my @param = map { defined($_) ? split /\s+/ : 'undef' } @list;
  21         123  
60 15         77 my $stmnt = substr "$class->new( @param )", 0, 80;
61 15         1452 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   2205 my ( $base, $string ) = @_;
92 994         1613 local $_ = $string;
93 994 100       2213 die 'argument absent or undefined' unless defined $_;
94 993 100       2070 die 'non-scalar argument' if ref $_;
95              
96             # parse into quoted strings, contiguous non-whitespace and (discarded) comments
97 991         2232 s/\\\\/\\092/g; # disguise escaped escape
98 991         1469 s/\\"/\\034/g; # disguise escaped quote
99 991         1465 s/\\\(/\\040/g; # disguise escaped bracket
100 991         1449 s/\\\)/\\041/g; # disguise escaped bracket
101 991         1519 s/\\;/\\059/g; # disguise escaped semicolon
102 991 100       15495 my ( $owner, @token ) = grep { defined && length } split /$PARSE_REGEX/o;
  8519         21651  
103              
104 991 100       2821 die 'unable to parse RR string' unless scalar @token;
105 990         1663 my $t1 = $token[0];
106 990         1592 my $t2 = $token[1];
107              
108 990         1480 my ( $ttl, $class );
109 990 100 100     5791 if ( not defined $t2 ) { #
    100          
    100          
110 65 100       376 @token = ('ANY') if $classbyname{uc $t1}; #
111             } elsif ( $t1 =~ /^\d/ ) {
112 234         401 $ttl = shift @token; # []
113 234 100 100     781 $class = shift @token if $classbyname{uc $t2} || $t2 =~ /^CLASS\d/i;
114             } elsif ( $classbyname{uc $t1} || $t1 =~ /^CLASS\d/i ) {
115 169         453 $class = shift @token; # []
116 169 100       643 $ttl = shift @token if $t2 =~ /^\d/;
117             }
118              
119 990         1848 my $type = shift(@token);
120 990         1530 my $populated = scalar @token;
121              
122 990         2470 my $self = $base->_subclass( $type, $populated ); # create RR object
123 989         3196 $self->owner($owner);
124 989         2511 &class( $self, $class ); # specify CLASS
125 989         2445 &ttl( $self, $ttl ); # specify TTL
126              
127 989 100       2303 return $self unless $populated; # empty RR
128              
129 897 100 100     3328 if ( $#token && $token[0] =~ /^[\\]?#$/ ) {
130 28         56 shift @token; # RFC3597 hexadecimal format
131 28   100     77 my $rdlen = shift(@token) || 0;
132 28         132 my $rdata = pack 'H*', join( '', @token );
133 28 100       111 die 'length and hexadecimal data inconsistent' unless $rdlen == length $rdata;
134 25         65 $self->rdata($rdata); # unpack RDATA
135             } else {
136 869         2499 $self->_parse_rdata(@token); # parse arguments
137             }
138              
139 873         2770 $self->_post_parse();
140 869         3385 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 594     594   1195 my $base = shift;
176              
177 594         2357 my %attribute = ( owner => '.', type => 'NULL' );
178 594         1809 while ( my $key = shift ) {
179 1371         4073 $attribute{lc $key} = shift;
180             }
181              
182 594         2889 my ( $owner, $name, $type, $class, $ttl ) = delete @attribute{@core};
183              
184 594         2431 my $self = $base->_subclass( $type, scalar(%attribute) );
185 594 100       2824 $self->owner( $name ? $name : $owner );
186 594 100       1471 $self->class($class) if defined $class; # optional CLASS
187 594 100       1375 $self->ttl($ttl) if defined $ttl; # optional TTL
188              
189 594         1030 eval {
190 594         2483 while ( my ( $attribute, $value ) = each %attribute ) {
191 466 100       2070 $self->$attribute( ref($value) eq 'ARRAY' ? @$value : $value );
192             }
193             };
194 594 100       1632 die ref($self) eq __PACKAGE__ ? "type $type not implemented" : () if $@;
    100          
195              
196 592         2218 $self->_post_parse();
197 592         2973 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   841 use constant RRFIXEDSZ => length pack 'n2 N n', (0) x 4;
  94         217  
  94         317496  
222              
223             sub decode {
224 9760     9760 1 22399 my ( $base, @argument ) = @_;
225              
226 9760         24522 my ( $owner, $fixed ) = Net::DNS::DomainName1035->decode(@argument);
227 9759         15803 my $index = $fixed + RRFIXEDSZ;
228 9759         16754 my ( $data, $offset, @opaque ) = @argument;
229 9759 100       19251 die 'corrupt wire-format data' if length $$data < $index;
230 9758         27391 my $self = $base->_subclass( unpack "\@$fixed n", $$data );
231 9758         18570 $self->{owner} = $owner;
232 9758         26082 @{$self}{qw(class ttl rdlength)} = unpack "\@$fixed x2 n N n", $$data;
  9758         25476  
233              
234 9758         17099 my $next = $index + $self->{rdlength};
235 9758 100       19060 die 'corrupt wire-format data' if length $$data < $next;
236              
237 9757         19057 local $self->{offset} = $offset;
238 9757 100 100     36927 $self->_decode_rdata( $data, $index, @opaque ) if $next > $index or $self->type eq 'OPT';
239              
240 9751 100       35759 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 34492 my ( $self, $offset, @opaque ) = @_;
261 1112 100       2425 ( $offset, @opaque ) = ( 0x4000, {} ) unless defined $offset;
262              
263 1112         3014 my $owner = $self->{owner}->encode( $offset, @opaque );
264 1112         1798 my ( $type, $class, $ttl ) = @{$self}{qw(type class ttl)};
  1112         2452  
265 1112 100       2304 my $rdata = $self->_empty ? '' : $self->_encode_rdata( $offset + length($owner) + RRFIXEDSZ, @opaque );
266 1112   100     8756 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 515 my $self = shift;
285              
286 305         790 my $owner = $self->{owner}->canonical;
287 305         491 my ( $type, $class, $ttl ) = @{$self}{qw(type class ttl)};
  305         643  
288 305 100       610 my $rdata = $self->_empty ? '' : $self->_encode_rdata( length($owner) + RRFIXEDSZ );
289 305   100     2240 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 1006 print shift->string, "\n";
304 25         656 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 3875 my $self = shift;
321              
322 1159         4903 my $name = $self->{owner}->string;
323 1159         2695 my @ttl = grep {defined} $self->{ttl};
  1159         3299  
324 1159         3158 my @core = ( $name, @ttl, $self->class, $self->type );
325              
326 1159         3360 local $SIG{__DIE__};
327 1159         2542 my $empty = $self->_empty;
328 1159 100       2670 my @rdata = $empty ? () : eval { $self->_format_rdata };
  1125         2845  
329 1159 100       3106 carp $@ if $@;
330              
331 1159 100       2597 my $tab = length($name) < 72 ? "\t" : ' ';
332 1159         4197 my @line = _wrap( join( $tab, @core, '(' ), @rdata, ')' );
333              
334 1159         2206 my $last = pop(@line); # last or only line
335 1159 100       2766 $last = join $tab, @core, "@rdata" unless scalar(@line);
336              
337 1159 100       2327 $self->_annotation('no data') if $empty;
338 1159         2977 return join "\n\t", @line, _wrap( $last, map {"; $_"} $self->_annotation );
  66         261  
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 77 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 13 my $self = shift;
367              
368 7         16 my @ttl = grep {defined} $self->{ttl};
  7         19  
369 7         22 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       26 local $_ = $self->_empty ? '' : join( ' ', $self->_format_rdata );
373 7         18 s/\\\\/\\092/g; # disguise escaped escape
374 7         10 s/\\"/\\034/g; # disguise escaped quote
375 7         17 s/\\\(/\\040/g; # disguise escaped bracket
376 7         9 s/\\\)/\\041/g; # disguise escaped bracket
377 7         11 s/\\;/\\059/g; # disguise escaped semicolon
378 7 100       95 return ( @core, grep { defined && length } split /$PARSE_REGEX/o );
  35         103  
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 19 my $self = shift;
394              
395 8         23 my @ttl = grep {defined} $self->{ttl};
  8         28  
396 8         19 my @class = map {"CLASS$_"} grep {defined} $self->{class};
  3         11  
  8         20  
397 8         41 my @core = ( $self->{owner}->string, @ttl, @class, "TYPE$self->{type}" );
398 8         27 my $data = $self->rdata;
399 8         56 my @data = ( '\\#', length($data), split /(\S{32})/, unpack 'H*', $data );
400 8         39 my @line = _wrap( "@core (", @data, ')' );
401 8 100       49 return join "\n\t", @line if scalar(@line) > 1;
402 7         49 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 4238     4238 1 8393 my ( $self, @name ) = @_;
416 4238         7327 for (@name) { $self->{owner} = Net::DNS::DomainName1035->new($_) }
  1583         6555  
417 4238 100       10806 return defined wantarray ? $self->{owner}->name : undef;
418             }
419              
420 435     435 1 7320 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 2417     2417 1 4666 my ( $self, @value ) = @_;
433 2417         4610 for (@value) { croak 'not possible to change RR->type' }
  1         71  
434 2416         6142 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 7008 my ( $self, $class ) = @_;
448 2797 100       6148 return $self->{class} = classbyname($class) if defined $class;
449 1981 100       5930 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 3847 my ( $self, $time ) = @_;
469              
470 1447 100 100     3849 return $self->{ttl} || 0 unless defined $time; # avoid defining rr->{ttl}
471              
472 633         856 my $ttl = 0;
473 633         3197 my %time = reverse split /(\D)\D*/, $time . 'S';
474 633         2236 while ( my ( $u, $t ) = each %time ) {
475 633   100     1596 my $scale = $unit{uc $u} || die qq(bad time: $t$u);
476 632         2098 $ttl += $t * $scale;
477             }
478 632         2608 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   6 my ( $self, $data, $offset ) = @_;
490 3         10 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   18 return shift->{rdata};
496             }
497              
498              
499             sub _format_rdata { ## format rdata portion of RR string
500 7     7   28 my $rdata = shift->rdata; # RFC3597 unknown RR format
501 7         45 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   3 my $self = shift;
507 2 100       8 die join ' ', 'type', $self->type, 'not implemented' if ref($self) eq __PACKAGE__;
508 1         8 die join ' ', 'no zone file representation defined for', $self->type;
509             }
510              
511              
512       1435     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 143 my @data = @_; # uncoverable pod
520 2         10 require Data::Dumper;
521 2   100     44 local $Data::Dumper::Maxdepth = $Data::Dumper::Maxdepth || 6;
522 2   100     10 local $Data::Dumper::Sortkeys = $Data::Dumper::Sortkeys || 1;
523 2   100     23 local $Data::Dumper::Useqq = $Data::Dumper::Useqq || 1;
524 2         10 return print Data::Dumper::Dumper(@data);
525             }
526              
527             sub rdatastr { ## historical RR subtype method
528 2     2 0 6 my $self = shift; # uncoverable pod
529 2         11 $self->_deprecate('prefer $rr->rdstring()');
530 2         10 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 2090 my $self = shift;
544              
545 167 100       750 return $self->_empty ? '' : eval { $self->_encode_rdata( 0x4000, {} ) } unless @_;
  117 100       497  
546              
547 30   100     78 my $data = shift || '';
548 30 100       135 $self->_decode_rdata( \$data, 0 ) if ( $self->{rdlength} = length $data );
549 28         71 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 3564 my $self = shift;
563 88         270 local $SIG{__DIE__};
564              
565 88 100       217 my @rdata = $self->_empty ? () : eval { $self->_format_rdata };
  69         194  
566 88 100       314 carp $@ if $@;
567              
568 88         254 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 76 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 144 my $class = shift;
623 42         75 my $attribute = shift;
624 42         72 my $function = shift;
625              
626 42         357 my ($type) = $class =~ m/::([^:]+)$/;
627 42         164 $rrsortfunct{$type}{$attribute} = $function;
628 42         120 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 1682 my $class = shift;
645 13   100     56 my $attribute = shift || 'default_sort';
646              
647 13         113 my ($type) = $class =~ m/::([^:]+)$/;
648              
649 13   100     72 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 11342     11342   21939 my ( $class, $rrname, $default ) = @_;
671              
672 11342 100       26552 unless ( $_LOADED{$rrname} ) {
673 180         919 my $rrtype = typebyname($rrname);
674              
675 179 100       652 unless ( $_LOADED{$rrtype} ) { # load once only
676 170         1151 local @INC = LIB;
677              
678 170         587 my $identifier = typebyval($rrtype);
679 170         672 $identifier =~ s/\W/_/g; # kosher Perl identifier
680              
681 170         661 my $subclass = join '::', __PACKAGE__, $identifier;
682              
683 170 100       12247 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   5 my @line = split /\n/, $perl;
688 1         71 return ( sub { defined( $_ = shift @line ) } );
  1         38  
689 1         8 };
690 1         57 eval "require $subclass"; ## no critic ProhibitStringyEval
691             }
692              
693 170 100       942 $subclass = __PACKAGE__ if $@;
694              
695             # cache pre-built minimal and populated default object images
696 170         776 my @base = ( 'type' => $rrtype );
697 170         1007 $_MINIMAL{$rrtype} = bless [@base], $subclass;
698              
699 170         641 my $object = bless {@base}, $subclass;
700 170         1184 $object->_defaults;
701 170         2134 $_LOADED{$rrtype} = bless [%$object], $subclass;
702             }
703              
704 179         686 $_MINIMAL{$rrname} = $_MINIMAL{$rrtype};
705 179         502 $_LOADED{$rrname} = $_LOADED{$rrtype};
706             }
707              
708 11341 100       21483 my $prebuilt = $default ? $_LOADED{$rrname} : $_MINIMAL{$rrname};
709 11341         46772 return bless {@$prebuilt}, ref($prebuilt); # create object
710             }
711              
712              
713             sub _annotation {
714 1227     1227   7774 my ( $self, @note ) = @_;
715 1227 100       2538 $self->{annotation} = ["@note"] if scalar @note;
716 1227 100       2379 return wantarray ? @{$self->{annotation} || []} : ();
  1159 100       5505  
717             }
718              
719              
720             my %warned;
721              
722             sub _deprecate {
723 9     9   29 my ( undef, @note ) = @_;
724 9 100       763 carp "deprecated method; @note" unless $warned{"@note"}++;
725 9         282 return;
726             }
727              
728              
729             my %ignore = map { ( $_ => 1 ) } @core, 'annotation', '#';
730              
731             sub _empty {
732 2808     2808   3858 my $self = shift;
733 2808   100     12042 return not( $self->{'#'} ||= scalar grep { !$ignore{$_} } keys %$self );
  8186         17552  
734             }
735              
736              
737             sub _wrap {
738 2435     2435   5458 my @text = @_;
739 2435         3082 my $cols = 80;
740 2435         2945 my $coln = 0;
741              
742 2435         3108 my ( @line, @fill );
743 2435         4027 foreach (@text) {
744 5665   100     9877 $coln += ( length || next ) + 1;
745 5627 100       9546 if ( $coln > $cols ) { # start new line
746 1763 100       4210 push( @line, join ' ', @fill ) if @fill;
747 1763         2523 $coln = length;
748 1763         2467 @fill = ();
749             }
750 5627 100       9671 $coln = $cols if chomp; # force line break
751 5627 100       11607 push( @fill, $_ ) if length;
752             }
753 2435         15109 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   598 my ($self) = @_;
764              
765 94     94   961 no strict 'refs'; ## no critic ProhibitNoStrict
  94         276  
  94         35389  
766 10         18 our $AUTOLOAD;
767 10         51 my ($method) = reverse split /::/, $AUTOLOAD;
768              
769 10         41 for ( my $action = $method ) { ## tolerate mixed-case attribute name
770 10         23 tr [A-Z-] [a-z_];
771 10 100       74 if ( $self->can($action) ) {
772 7     19   51 *{$AUTOLOAD} = sub { shift->$action(@_) };
  7         43  
  19         2085  
773 7         33 return &$AUTOLOAD;
774             }
775             }
776              
777 3         7 my $oref = ref($self);
778 3     1   11 *{$AUTOLOAD} = sub {}; ## suppress deep recursion
  3         39  
779 3 100       233 croak qq[$self has no class method "$method"] unless $oref;
780              
781 2         7 my $string = $self->string;
782 2         20 my @object = grep { defined($_) } $oref, $oref->VERSION;
  4         14  
783 2         8 my $module = join '::', __PACKAGE__, $self->type;
784 2 100       81 eval("require $module") if $oref eq __PACKAGE__; ## no critic ProhibitStringyEval
785              
786 2         17 @_ = ( <<"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         515 goto &Carp::confess;
800             }
801              
802              
803             1;
804             __END__