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   1537 use strict;
  94         181  
  94         2957  
4 94     94   471 use warnings;
  94         182  
  94         4765  
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   1023 use integer;
  94         178  
  94         439  
35 94     94   1915 use Carp;
  94         236  
  94         8890  
36              
37 94     94   699 use constant LIB => grep { $_ ne '.' } grep { !ref($_) } @INC;
  94         194  
  94         249  
  1128         10462  
  1128         1981  
38              
39 94     94   43883 use Net::DNS::Parameters qw(%classbyname :class :type);
  94         341  
  94         17089  
40 94     94   42110 use Net::DNS::DomainName;
  94         282  
  94         82935  
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 391812 my ( $class, @list ) = @_;
54 1304         2639 my $rr = eval {
55 1304         4364 local $SIG{__DIE__};
56 1304 100       4562 scalar @list > 1 ? &_new_hash : &_new_string;
57             };
58 1304 100       6131 return $rr if $rr;
59 15 100       51 my @param = map { defined($_) ? split /\s+/ : 'undef' } @list;
  21         127  
60 15         71 my $stmnt = substr "$class->new( @param )", 0, 80;
61 15         1474 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   2009 my ( $base, $string ) = @_;
92 994         1693 local $_ = $string;
93 994 100       2152 die 'argument absent or undefined' unless defined $_;
94 993 100       2170 die 'non-scalar argument' if ref $_;
95              
96             # parse into quoted strings, contiguous non-whitespace and (discarded) comments
97 991         2171 s/\\\\/\\092/g; # disguise escaped escape
98 991         1502 s/\\"/\\034/g; # disguise escaped quote
99 991         1496 s/\\\(/\\040/g; # disguise escaped bracket
100 991         1420 s/\\\)/\\041/g; # disguise escaped bracket
101 991         1507 s/\\;/\\059/g; # disguise escaped semicolon
102 991 100       15245 my ( $owner, @token ) = grep { defined && length } split /$PARSE_REGEX/o;
  8519         21735  
103              
104 991 100       2799 die 'unable to parse RR string' unless scalar @token;
105 990         1644 my $t1 = $token[0];
106 990         1431 my $t2 = $token[1];
107              
108 990         1469 my ( $ttl, $class );
109 990 100 100     6551 if ( not defined $t2 ) { #
    100          
    100          
110 65 100       340 @token = ('ANY') if $classbyname{uc $t1}; #
111             } elsif ( $t1 =~ /^\d/ ) {
112 234         387 $ttl = shift @token; # []
113 234 100 100     787 $class = shift @token if $classbyname{uc $t2} || $t2 =~ /^CLASS\d/i;
114             } elsif ( $classbyname{uc $t1} || $t1 =~ /^CLASS\d/i ) {
115 169         432 $class = shift @token; # []
116 169 100       658 $ttl = shift @token if $t2 =~ /^\d/;
117             }
118              
119 990         1752 my $type = shift(@token);
120 990         1527 my $populated = scalar @token;
121              
122 990         2467 my $self = $base->_subclass( $type, $populated ); # create RR object
123 989         3076 $self->owner($owner);
124 989         2377 &class( $self, $class ); # specify CLASS
125 989         2605 &ttl( $self, $ttl ); # specify TTL
126              
127 989 100       2198 return $self unless $populated; # empty RR
128              
129 897 100 100     3470 if ( $#token && $token[0] =~ /^[\\]?#$/ ) {
130 28         52 shift @token; # RFC3597 hexadecimal format
131 28   100     74 my $rdlen = shift(@token) || 0;
132 28         142 my $rdata = pack 'H*', join( '', @token );
133 28 100       115 die 'length and hexadecimal data inconsistent' unless $rdlen == length $rdata;
134 25         71 $self->rdata($rdata); # unpack RDATA
135             } else {
136 869         2561 $self->_parse_rdata(@token); # parse arguments
137             }
138              
139 873         2768 $self->_post_parse();
140 869         3348 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   1189 my $base = shift;
176              
177 597         2081 my %attribute = ( owner => '.', type => 'NULL' );
178 597         1819 while ( my $key = shift ) {
179 1374         3937 $attribute{lc $key} = shift;
180             }
181              
182 597         2842 my ( $owner, $name, $type, $class, $ttl ) = delete @attribute{@core};
183              
184 597         2275 my $self = $base->_subclass( $type, scalar(%attribute) );
185 597 100       2916 $self->owner( $name ? $name : $owner );
186 597 100       1495 $self->class($class) if defined $class; # optional CLASS
187 597 100       1400 $self->ttl($ttl) if defined $ttl; # optional TTL
188              
189 597         938 eval {
190 597         2282 while ( my ( $attribute, $value ) = each %attribute ) {
191 466 100       1985 $self->$attribute( ref($value) eq 'ARRAY' ? @$value : $value );
192             }
193             };
194 597 100       1589 die ref($self) eq __PACKAGE__ ? "type $type not implemented" : () if $@;
    100          
195              
196 595         2055 $self->_post_parse();
197 595         2839 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   813 use constant RRFIXEDSZ => length pack 'n2 N n', (0) x 4;
  94         219  
  94         307344  
222              
223             sub decode {
224 9853     9853 1 22688 my ( $base, @argument ) = @_;
225              
226 9853         22535 my ( $owner, $fixed ) = Net::DNS::DomainName1035->decode(@argument);
227 9852         14347 my $index = $fixed + RRFIXEDSZ;
228 9852         16353 my ( $data, $offset, @opaque ) = @argument;
229 9852 100       18938 die 'corrupt wire-format data' if length $$data < $index;
230 9851         26107 my $self = $base->_subclass( unpack "\@$fixed n", $$data );
231 9851         16741 $self->{owner} = $owner;
232 9851         24812 @{$self}{qw(class ttl rdlength)} = unpack "\@$fixed x2 n N n", $$data;
  9851         23659  
233              
234 9851         16143 my $next = $index + $self->{rdlength};
235 9851 100       18196 die 'corrupt wire-format data' if length $$data < $next;
236              
237 9850         17720 local $self->{offset} = $offset;
238 9850 100 100     34758 $self->_decode_rdata( $data, $index, @opaque ) if $next > $index or $self->type eq 'OPT';
239              
240 9844 100       32586 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 34265 my ( $self, $offset, @opaque ) = @_;
261 1112 100       2398 ( $offset, @opaque ) = ( 0x4000, {} ) unless defined $offset;
262              
263 1112         3035 my $owner = $self->{owner}->encode( $offset, @opaque );
264 1112         1798 my ( $type, $class, $ttl ) = @{$self}{qw(type class ttl)};
  1112         2417  
265 1112 100       2327 my $rdata = $self->_empty ? '' : $self->_encode_rdata( $offset + length($owner) + RRFIXEDSZ, @opaque );
266 1112   100     8586 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 470 my $self = shift;
285              
286 305         688 my $owner = $self->{owner}->canonical;
287 305         472 my ( $type, $class, $ttl ) = @{$self}{qw(type class ttl)};
  305         622  
288 305 100       578 my $rdata = $self->_empty ? '' : $self->_encode_rdata( length($owner) + RRFIXEDSZ );
289 305   100     2192 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 846 print shift->string, "\n";
304 25         689 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 3569 my $self = shift;
321              
322 1159         3729 my $name = $self->{owner}->string;
323 1159         2701 my @ttl = grep {defined} $self->{ttl};
  1159         3147  
324 1159         2970 my @core = ( $name, @ttl, $self->class, $self->type );
325              
326 1159         3381 local $SIG{__DIE__};
327 1159         2633 my $empty = $self->_empty;
328 1159 100       3179 my @rdata = $empty ? () : eval { $self->_format_rdata };
  1125         2748  
329 1159 100       3242 carp $@ if $@;
330              
331 1159 100       2567 my $tab = length($name) < 72 ? "\t" : ' ';
332 1159         4107 my @line = _wrap( join( $tab, @core, '(' ), @rdata, ')' );
333              
334 1159         2186 my $last = pop(@line); # last or only line
335 1159 100       2755 $last = join $tab, @core, "@rdata" unless scalar(@line);
336              
337 1159 100       2150 $self->_annotation('no data') if $empty;
338 1159         2849 return join "\n\t", @line, _wrap( $last, map {"; $_"} $self->_annotation );
  66         254  
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 54 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         14 my @ttl = grep {defined} $self->{ttl};
  7         19  
369 7         21 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         16 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         12 s/\\\)/\\041/g; # disguise escaped bracket
377 7         7 s/\\;/\\059/g; # disguise escaped semicolon
378 7 100       91 return ( @core, grep { defined && length } split /$PARSE_REGEX/o );
  35         100  
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 18 my $self = shift;
394              
395 8         30 my @ttl = grep {defined} $self->{ttl};
  8         26  
396 8         17 my @class = map {"CLASS$_"} grep {defined} $self->{class};
  3         11  
  8         19  
397 8         32 my @core = ( $self->{owner}->string, @ttl, @class, "TYPE$self->{type}" );
398 8         28 my $data = $self->rdata;
399 8         49 my @data = ( '\\#', length($data), split /(\S{32})/, unpack 'H*', $data );
400 8         35 my @line = _wrap( "@core (", @data, ')' );
401 8 100       27 return join "\n\t", @line if scalar(@line) > 1;
402 7         41 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 4318     4318 1 7869 my ( $self, @name ) = @_;
416 4318         7266 for (@name) { $self->{owner} = Net::DNS::DomainName1035->new($_) }
  1586         6081  
417 4318 100       10441 return defined wantarray ? $self->{owner}->name : undef;
418             }
419              
420 439     439 1 8088 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 2498     2498 1 4756 my ( $self, @value ) = @_;
433 2498         4488 for (@value) { croak 'not possible to change RR->type' }
  1         73  
434 2497         5970 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 7191 my ( $self, $class ) = @_;
448 2797 100       6276 return $self->{class} = classbyname($class) if defined $class;
449 1981 100       6125 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 3946 my ( $self, $time ) = @_;
469              
470 1447 100 100     3783 return $self->{ttl} || 0 unless defined $time; # avoid defining rr->{ttl}
471              
472 633         825 my $ttl = 0;
473 633         3176 my %time = reverse split /(\D)\D*/, $time . 'S';
474 633         2235 while ( my ( $u, $t ) = each %time ) {
475 633   100     1645 my $scale = $unit{uc $u} || die qq(bad time: $t$u);
476 632         2617 $ttl += $t * $scale;
477             }
478 632         1838 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         11 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   16 return shift->{rdata};
496             }
497              
498              
499             sub _format_rdata { ## format rdata portion of RR string
500 7     7   18 my $rdata = shift->rdata; # RFC3597 unknown RR format
501 7         44 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         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 128 my @data = @_; # uncoverable pod
520 2         10 require Data::Dumper;
521 2   100     9 local $Data::Dumper::Maxdepth = $Data::Dumper::Maxdepth || 6;
522 2   100     8 local $Data::Dumper::Sortkeys = $Data::Dumper::Sortkeys || 1;
523 2   100     15 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         8 $self->_deprecate('prefer $rr->rdstring()');
530 2         6 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 2297 my $self = shift;
544              
545 167 100       723 return $self->_empty ? '' : eval { $self->_encode_rdata( 0x4000, {} ) } unless @_;
  117 100       444  
546              
547 30   100     75 my $data = shift || '';
548 30 100       137 $self->_decode_rdata( \$data, 0 ) if ( $self->{rdlength} = length $data );
549 28         67 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 4040 my $self = shift;
563 88         273 local $SIG{__DIE__};
564              
565 88 100       213 my @rdata = $self->_empty ? () : eval { $self->_format_rdata };
  69         189  
566 88 100       325 carp $@ if $@;
567              
568 88         225 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 63 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 123 my $class = shift;
623 42         84 my $attribute = shift;
624 42         71 my $function = shift;
625              
626 42         325 my ($type) = $class =~ m/::([^:]+)$/;
627 42         142 $rrsortfunct{$type}{$attribute} = $function;
628 42         111 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 1604 my $class = shift;
645 13   100     42 my $attribute = shift || 'default_sort';
646              
647 13         88 my ($type) = $class =~ m/::([^:]+)$/;
648              
649 13   100     54 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 11438     11438   20653 my ( $class, $rrname, $default ) = @_;
671              
672 11438 100       24797 unless ( $_LOADED{$rrname} ) {
673 180         916 my $rrtype = typebyname($rrname);
674              
675 179 100       661 unless ( $_LOADED{$rrtype} ) { # load once only
676 170         1010 local @INC = LIB;
677              
678 170         589 my $identifier = typebyval($rrtype);
679 170         624 $identifier =~ s/\W/_/g; # kosher Perl identifier
680              
681 170         622 my $subclass = join '::', __PACKAGE__, $identifier;
682              
683 170 100       11954 unless ( eval "require $subclass" ) { ## no critic ProhibitStringyEval
684 1         7 my $perl = Net::DNS::Parameters::_typespec("$rrtype.RRTYPE");
685 1         4 $subclass = join '::', __PACKAGE__, "TYPE$rrtype";
686             push @INC, sub { # see perldoc -f require
687 1     1   6 my @line = split /\n/, $perl;
688 1         57 return ( sub { defined( $_ = shift @line ) } );
  1         37  
689 1         7 };
690 1         54 eval "require $subclass"; ## no critic ProhibitStringyEval
691             }
692              
693 170 100       852 $subclass = __PACKAGE__ if $@;
694              
695             # cache pre-built minimal and populated default object images
696 170         765 my @base = ( 'type' => $rrtype );
697 170         1025 $_MINIMAL{$rrtype} = bless [@base], $subclass;
698              
699 170         633 my $object = bless {@base}, $subclass;
700 170         1214 $object->_defaults;
701 170         2192 $_LOADED{$rrtype} = bless [%$object], $subclass;
702             }
703              
704 179         670 $_MINIMAL{$rrname} = $_MINIMAL{$rrtype};
705 179         461 $_LOADED{$rrname} = $_LOADED{$rrtype};
706             }
707              
708 11437 100       20993 my $prebuilt = $default ? $_LOADED{$rrname} : $_MINIMAL{$rrname};
709 11437         40369 return bless {@$prebuilt}, ref($prebuilt); # create object
710             }
711              
712              
713             sub _annotation {
714 1227     1227   7763 my ( $self, @note ) = @_;
715 1227 100       2537 $self->{annotation} = ["@note"] if scalar @note;
716 1227 100       2447 return wantarray ? @{$self->{annotation} || []} : ();
  1159 100       5723  
717             }
718              
719              
720             my %warned;
721              
722             sub _deprecate {
723 9     9   23 my ( undef, @note ) = @_;
724 9 100       707 carp "deprecated method; @note" unless $warned{"@note"}++;
725 9         274 return;
726             }
727              
728              
729             my %ignore = map { ( $_ => 1 ) } @core, 'annotation', '#';
730              
731             sub _empty {
732 2808     2808   3876 my $self = shift;
733 2808   100     11949 return not( $self->{'#'} ||= scalar grep { !$ignore{$_} } keys %$self );
  8186         17793  
734             }
735              
736              
737             sub _wrap {
738 2435     2435   5445 my @text = @_;
739 2435         3141 my $cols = 80;
740 2435         2890 my $coln = 0;
741              
742 2435         3149 my ( @line, @fill );
743 2435         4065 foreach (@text) {
744 5665   100     10597 $coln += ( length || next ) + 1;
745 5627 100       8879 if ( $coln > $cols ) { # start new line
746 1763 100       4296 push( @line, join ' ', @fill ) if @fill;
747 1763         2408 $coln = length;
748 1763         2443 @fill = ();
749             }
750 5627 100       9486 $coln = $cols if chomp; # force line break
751 5627 100       11473 push( @fill, $_ ) if length;
752             }
753 2435         15812 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   556 my ($self) = @_;
764              
765 94     94   910 no strict 'refs'; ## no critic ProhibitNoStrict
  94         272  
  94         35072  
766 10         18 our $AUTOLOAD;
767 10         49 my ($method) = reverse split /::/, $AUTOLOAD;
768              
769 10         38 for ( my $action = $method ) { ## tolerate mixed-case attribute name
770 10         26 tr [A-Z-] [a-z_];
771 10 100       85 if ( $self->can($action) ) {
772 7     19   73 *{$AUTOLOAD} = sub { shift->$action(@_) };
  7         50  
  19         2000  
773 7         40 return &$AUTOLOAD;
774             }
775             }
776              
777 3         6 my $oref = ref($self);
778 3     1   9 *{$AUTOLOAD} = sub {}; ## suppress deep recursion
  3         30  
779 3 100       192 croak qq[$self has no class method "$method"] unless $oref;
780              
781 2         9 my $string = $self->string;
782 2         22 my @object = grep { defined($_) } $oref, $oref->VERSION;
  4         13  
783 2         8 my $module = join '::', __PACKAGE__, $self->type;
784 2 100       60 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         526 goto &Carp::confess;
800             }
801              
802              
803             1;
804             __END__