File Coverage

blib/lib/Net/DNS/RR.pm
Criterion Covered Total %
statement 294 294 100.0
branch 142 142 100.0
path n/a
condition 42 42 100.0
subroutine 48 48 100.0
pod 19 21 100.0
total 545 547 100.0


line stmt bran path cond sub pod time code
1               package Net::DNS::RR;
2                
3 96       96   217328 use strict;
  96           156  
  96           2982  
4 96       96   371 use warnings;
  96           124  
  96           7374  
5                
6               our $VERSION = (qw$Id: RR.pm 2037 2025-08-18 14:39:32Z 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 96       96   816 use integer;
  96           150  
  96           478  
35 96       96   1694 use Carp;
  96           138  
  96           9119  
36                
37 96       96   508 use constant LIB => grep { $_ ne '.' } grep { !ref($_) } @INC;
  96           168  
  96           243  
  864           8371  
  864           1294  
38                
39 96       96   42716 use Net::DNS::Parameters qw(%classbyname :class :type);
  96           281  
  96           18250  
40 96       96   40912 use Net::DNS::DomainName;
  96           307  
  96           83945  
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 1318       1318 1 11041737 my ( $class, @list ) = @_;
54 1318           2204 my $rr = eval {
55 1318           4981 local $SIG{__DIE__};
56 1318 100         4210 scalar @list > 1 ? &_new_hash : &_new_string;
57               };
58 1318 100         5433 return $rr if $rr;
59 24 100         45 my @param = map { defined($_) ? split /\s+/ : 'undef' } @list;
  30           105  
60 24           111 my $stmnt = substr "$class->new( @param )", 0, 80;
61 24           2175 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 1020       1020   1944 my ( $base, $string ) = @_;
92 1020 100         2292 die 'argument absent or undefined' unless defined $string;
93 1019 100         1876 die 'non-scalar argument' if ref $string;
94                
95               # parse into quoted strings, contiguous non-whitespace and (discarded) comments
96 1017           1581 local $_ = $string;
97 1017           1884 s/\\\\/\\092/g; # disguise escaped escape
98 1017           1407 s/\\"/\\034/g; # disguise escaped quote
99 1017           2172 s/\\\(/\\040/g; # disguise escaped bracket
100 1017           1427 s/\\\)/\\041/g; # disguise escaped bracket
101 1017           1430 s/\\;/\\059/g; # disguise escaped semicolon
102 1017 100         28074 my ( $owner, @token ) = grep { defined && length } split /$PARSE_REGEX/o;
  9261           20441  
103                
104 1017 100         2380 die 'unable to parse RR string' unless scalar @token;
105 1016           1473 my $t1 = $token[0];
106 1016           1324 my $t2 = $token[1];
107                
108 1016           1310 my ( $ttl, $class );
109 1016 100   100     5314 if ( not defined $t2 ) { #
    100            
    100            
110 70 100         362 @token = ('ANY') if $classbyname{uc $t1}; #
111               } elsif ( $t1 =~ /^\d/ ) {
112 495           698 $ttl = shift @token; # []
113 495 100   100     1498 $class = shift @token if $classbyname{uc $t2} || $t2 =~ /^CLASS\d/i;
114               } elsif ( $classbyname{uc $t1} || $t1 =~ /^CLASS\d/i ) {
115 53           98 $class = shift @token; # []
116 53 100         142 $ttl = shift @token if $t2 =~ /^\d/;
117               }
118                
119 1016           1640 my $type = shift(@token);
120 1016           1508 my $populated = scalar @token;
121                
122 1016           2661 my $self = $base->_subclass( $type, $populated ); # create RR object
123 1015           3595 $self->owner($owner);
124 1015           2375 &class( $self, $class ); # specify CLASS
125 1015           2267 &ttl( $self, $ttl ); # specify TTL
126                
127 1015 100         2262 return $self unless $populated; # empty RR
128                
129 926 100   100     2624 if ( $#token && $token[0] =~ /^[\\]?#$/ ) {
130 29           45 shift @token; # RFC3597 hexadecimal format
131 29     100     108 my $rdlen = shift(@token) || 0;
132 29           136 my $rdata = pack 'H*', join( '', @token );
133 29 100         136 die 'length and hexadecimal data inconsistent' unless $rdlen == length $rdata;
134 26           71 $self->rdata($rdata); # unpack RDATA
135               } else {
136 897           2192 $self->_parse_rdata(@token); # parse arguments
137               }
138                
139 901           2342 $self->_post_parse();
140 890           3511 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 585       585   1094 my $base = shift;
176                
177 585           2120 my %argument = ( owner => '.', type => 'NULL' );
178 585           897 my @attribute;
179 585           1683 while ( my $key = shift ) {
180 1371           2195 push @attribute, $key;
181 1371           3822 $argument{lc $key} = shift;
182               }
183                
184 585           2280 my ( $owner, $name, $type, $class, $ttl ) = delete @argument{@core};
185                
186 585           2222 my $self = $base->_subclass( $type, scalar(%argument) );
187 585 100         2559 $self->owner( $name ? $name : $owner );
188 585 100         1365 $self->class($class) if defined $class; # optional CLASS
189 585 100         1201 $self->ttl($ttl) if defined $ttl; # optional TTL
190                
191 585           826 eval {
192 585           1010 foreach my $attribute (@attribute) {
193 1371           2379 my $value = $argument{lc $attribute};
194 1371 100         2733 next unless defined $value;
195 473 100         1790 $self->$attribute( ref($value) eq 'ARRAY' ? @$value : $value );
196               }
197               };
198 585 100         1371 die ref($self) eq __PACKAGE__ ? "type $type not implemented" : () if $@;
    100            
199                
200 583           1835 $self->_post_parse();
201 583           3305 return $self;
202               }
203                
204                
205               =head2 decode
206                
207               ( $rr, $next ) = Net::DNS::RR->decode( \$data, $offset, @opaque );
208                
209               Decodes a DNS resource record at the specified location within a
210               DNS packet.
211                
212               The argument list consists of a reference to the buffer containing
213               the packet data and offset indicating where resource record begins.
214               Any remaining arguments are passed as opaque data to subordinate
215               decoders and do not form part of the published interface.
216                
217               Returns a C object and the offset of the next record
218               in the packet.
219                
220               An exception is raised if the data buffer contains insufficient or
221               corrupt data.
222                
223               =cut
224                
225 96       96   756 use constant RRFIXEDSZ => length pack 'n2 N n', (0) x 4;
  96           143  
  96           279441  
226                
227               sub decode {
228 10032       10032 1 17714 my ( $base, @argument ) = @_;
229                
230 10032           17817 my ( $owner, $fixed ) = Net::DNS::DomainName1035->decode(@argument);
231 10031           11728 my $index = $fixed + RRFIXEDSZ;
232 10031           13355 my ( $data, $offset, @opaque ) = @argument;
233 10031 100         13824 die 'corrupt wire-format data' if length $$data < $index;
234 10030           19802 my $self = $base->_subclass( unpack "\@$fixed n", $$data );
235 10030           12630 $self->{owner} = $owner;
236 10030           18482 @{$self}{qw(class ttl rdlength)} = unpack "\@$fixed x2 n N n", $$data;
  10030           17794  
237                
238 10030           12295 my $next = $index + $self->{rdlength};
239 10030 100         14352 die 'corrupt wire-format data' if length $$data < $next;
240                
241 10029 100   100     15496 if ( $next > $index or $self->type eq 'OPT' ) {
242 10028           17362 local $self->{offset} = $offset;
243 10028           11116 eval { $self->_decode_rdata( $data, $index, @opaque ) };
  10028           16688  
244 10028 100         17480 warn $@ if $@;
245               }
246                
247 10029 100         22204 return wantarray ? ( $self, $next ) : $self;
248               }
249                
250                
251               =head2 encode
252                
253               $data = $rr->encode( $offset, @opaque );
254                
255               Returns the C in binary format suitable for inclusion
256               in a DNS packet buffer.
257                
258               The offset indicates the intended location within the packet data
259               where the C is to be stored.
260                
261               Any remaining arguments are opaque data which are passed intact to
262               subordinate encoders.
263                
264               =cut
265                
266               sub encode {
267 1145       1145 1 37495 my ( $self, $offset, @opaque ) = @_;
268 1145 100         2009 ( $offset, @opaque ) = ( 0x4000, {} ) unless defined $offset;
269                
270 1145           2439 my $owner = $self->{owner}->encode( $offset, @opaque );
271 1145           1359 my ( $type, $class, $ttl ) = @{$self}{qw(type class ttl)};
  1145           2110  
272 1145 100         1842 my $rdata = $self->_empty ? '' : $self->_encode_rdata( $offset + length($owner) + RRFIXEDSZ, @opaque );
273 1145     100     6404 return pack 'a* n2 N n a*', $owner, $type, $class || 1, $ttl || 0, length $rdata, $rdata;
        100        
274               }
275                
276                
277               =head2 canonical
278                
279               $data = $rr->canonical;
280                
281               Returns the C in canonical binary format suitable for
282               DNSSEC signature validation.
283                
284               The absence of the associative array argument signals to subordinate
285               encoders that the canonical uncompressed form of embedded domain
286               names is to be used.
287                
288               =cut
289                
290               sub canonical {
291 305       305 1 374 my $self = shift;
292                
293 305           565 my $owner = $self->{owner}->canonical;
294 305           409 my ( $type, $class, $ttl ) = @{$self}{qw(type class ttl)};
  305           551  
295 305 100         490 my $rdata = $self->_empty ? '' : $self->_encode_rdata( length($owner) + RRFIXEDSZ );
296 305     100     1836 return pack 'a* n2 N n a*', $owner, $type, $class || 1, $ttl || 0, length $rdata, $rdata;
        100        
297               }
298                
299                
300               =head2 print
301                
302               $rr->print;
303                
304               Prints the resource record to the currently selected output filehandle.
305               Calls the string method to get the formatted RR representation.
306                
307               =cut
308                
309               sub print {
310 27       27 1 1729 print shift->string, "\n";
311 27           523 return;
312               }
313                
314                
315               =head2 string
316                
317               print $rr->string, "\n";
318                
319               Returns a string representation of the RR using the master file format
320               mandated by RFC1035.
321               All domain names are fully qualified with trailing dot.
322               This differs from RR attribute methods, which omit the trailing dot.
323                
324               =cut
325                
326               sub string {
327 1118       1118 1 4332 my $self = shift;
328                
329 1118           3176 my $owner = $self->{owner}->string;
330 1118 100         2513 my @ttl = defined $self->{ttl} ? $self->{ttl} : ();
331 1118 100         2452 my @class = defined $self->{class} ? $self->class : ();
332 1118           2986 my @core = ( $owner, @ttl, @class, $self->type );
333                
334 1118           2559 local $SIG{__DIE__};
335 1118           2012 my $empty = $self->_empty;
336 1118 100         2150 my @rdata = $empty ? () : eval { $self->_format_rdata };
  1093           2552  
337 1118 100         2278 carp $@ if $@;
338                
339 1118 100         2091 my $tab = length($owner) < 72 ? "\t" : ' ';
340 1118           2984 my @line = _wrap( join( $tab, @core, '(' ), @rdata, ')' );
341                
342 1118           2651 my $last = pop(@line); # last or only line
343 1118 100         2089 $last = join $tab, @core, "@rdata" unless scalar(@line);
344                
345 1118 100         1843 $self->_annotation('no data') if $empty;
346 1118           2345 return join "\n\t", @line, _wrap( $last, $self->_annotation );
347               }
348                
349                
350               =head2 plain
351                
352               $plain = $rr->plain;
353                
354               Returns a simplified single-line representation of the RR.
355               This facilitates interaction with programs like nsupdate
356               which have rudimentary parsers.
357                
358               =cut
359                
360               sub plain {
361 8       8 1 57 return join ' ', shift->token;
362               }
363                
364                
365               =head2 token
366                
367               @token = $rr->token;
368                
369               Returns a token list representation of the RR zone file string.
370                
371               =cut
372                
373               sub token {
374 7       7 1 14 my $self = shift;
375                
376 7 100         18 my @ttl = defined $self->{ttl} ? $self->{ttl} : ();
377 7 100         21 my @class = defined $self->{class} ? $self->class : ();
378 7           28 my @core = ( $self->{owner}->string, @ttl, @class, $self->type );
379                
380               # parse into quoted strings, contiguous non-whitespace and (discarded) comments
381 7 100         53 local $_ = $self->_empty ? '' : join( ' ', $self->_format_rdata );
382 7           20 s/\\\\/\\092/g; # disguise escaped escape
383 7           11 s/\\"/\\034/g; # disguise escaped quote
384 7           11 s/\\\(/\\040/g; # disguise escaped bracket
385 7           10 s/\\\)/\\041/g; # disguise escaped bracket
386 7           15 s/\\;/\\059/g; # disguise escaped semicolon
387 7 100         127 return ( @core, grep { defined && length } split /$PARSE_REGEX/o );
  35           150  
388               }
389                
390                
391               =head2 generic
392                
393               $generic = $rr->generic;
394                
395               Returns the generic RR representation defined in RFC3597. This facilitates
396               creation of zone files containing RRs unrecognised by outdated nameservers
397               and provisioning software.
398                
399               =cut
400                
401               sub generic {
402 8       8 1 21 my $self = shift;
403                
404 8 100         28 my @ttl = defined $self->{ttl} ? $self->{ttl} : ();
405 8 100         29 my @class = defined $self->{class} ? "CLASS$self->{class}" : ();
406 8           38 my @core = ( $self->{owner}->string, @ttl, @class, "TYPE$self->{type}" );
407 8           31 my $data = $self->rdata;
408 8           54 my @data = ( '\\#', length($data), split /(\S{32})/, unpack 'H*', $data );
409 8           46 my @line = _wrap( "@core (", @data, ')' );
410 8 100         33 return join "\n\t", @line if scalar(@line) > 1;
411 7           902 return join ' ', @core, @data;
412               }
413                
414                
415               =head2 owner name
416                
417               $name = $rr->owner;
418                
419               Returns the owner name of the record.
420                
421               =cut
422                
423               sub owner {
424 2301       2301 1 4469 my ( $self, @name ) = @_;
425 2301           3552 for (@name) { $self->{owner} = Net::DNS::DomainName1035->new($_) }
  1600           5902  
426 2301 100         5428 return defined wantarray ? $self->{owner}->name : undef;
427               }
428                
429 424       424 1 7574 sub name { return &owner; } ## historical
430                
431                
432               =head2 type
433                
434               $type = $rr->type;
435                
436               Returns the record type.
437                
438               =cut
439                
440               sub type {
441 2207       2207 1 3272 my ( $self, @value ) = @_;
442 2207           3201 for (@value) { croak 'not possible to change RR->type' }
  1           108  
443 2206           4444 return typebyval( $self->{type} );
444               }
445                
446                
447               =head2 class
448                
449               $class = $rr->class;
450                
451               Resource record class.
452                
453               =cut
454                
455               sub class {
456 2527       2527 1 6224 my ( $self, $class ) = @_;
457 2527 100         5063 return $self->{class} = classbyname($class) if defined $class;
458 1560 100         3734 return defined $self->{class} ? classbyval( $self->{class} ) : 'IN';
459               }
460                
461                
462               =head2 ttl
463                
464               $ttl = $rr->ttl;
465               $ttl = $rr->ttl(3600);
466                
467               Resource record time to live in seconds.
468                
469               =cut
470                
471               # The following time units are recognised, but are not part of the
472               # published API. These are required for parsing BIND zone files but
473               # should not be used in other contexts.
474               my %unit = ( W => 604800, D => 86400, H => 3600, M => 60, S => 1 );
475                
476               sub ttl {
477 1129       1129 1 2032 my ( $self, $time ) = @_;
478                
479 1129 100   100     2710 return $self->{ttl} || 0 unless defined $time; # avoid defining rr->{ttl}
480                
481 596           837 my $ttl = 0;
482 596           2603 my %time = reverse split /(\D)\D*/, $time . 'S';
483 596           1612 while ( my ( $u, $t ) = each %time ) {
484 596     100     1279 my $scale = $unit{uc $u} || die qq(bad time: $t$u);
485 595           1626 $ttl += $t * $scale;
486               }
487 595           1396 return $self->{ttl} = $ttl;
488               }
489                
490                
491               ################################################################################
492               ##
493               ## Default implementation for unknown RR type
494               ##
495               ################################################################################
496                
497               sub _decode_rdata { ## decode rdata from wire-format octet string
498 7       7   23 my ( $self, $data, $offset ) = @_;
499 7           30 return $self->{rdata} = substr $$data, $offset, $self->{rdlength};
500               }
501                
502                
503               sub _encode_rdata { ## encode rdata as wire-format octet string
504 12       12   55 return shift->{rdata};
505               }
506                
507                
508               sub _format_rdata { ## format rdata portion of RR string
509 7       7   19 my $rdata = shift->rdata; # RFC3597 unknown RR format
510 7           68 return ( '\\#', length($rdata), split /(\S{32})/, unpack 'H*', $rdata );
511               }
512                
513                
514               sub _parse_rdata { ## parse RR attributes in argument list
515 2       2   2 my $self = shift;
516 2 100         7 die join ' ', 'type', $self->type, 'not implemented' if ref($self) eq __PACKAGE__;
517 1           4 die join ' ', 'no zone file representation defined for', $self->type;
518               }
519                
520                
521         1430     sub _post_parse { } ## parser post processing
522                
523                
524         117     sub _defaults { } ## set attribute default values
525                
526                
527               sub dump { ## print internal data structure
528 2       2 0 98 my @data = @_; # uncoverable pod
529 2           9 require Data::Dumper;
530 2     100     6 local $Data::Dumper::Maxdepth = $Data::Dumper::Maxdepth || 6;
531 2     100     5 local $Data::Dumper::Sortkeys = $Data::Dumper::Sortkeys || 1;
532 2     100     5 local $Data::Dumper::Useqq = $Data::Dumper::Useqq || 1;
533 2           3 return print Data::Dumper::Dumper(@data);
534               }
535                
536               sub rdatastr { ## historical RR subtype method
537 2       2 0 3 my $self = shift; # uncoverable pod
538 2           5 $self->_deprecate('prefer $rr->rdstring()');
539 2           5 return $self->rdstring;
540               }
541                
542                
543               =head2 rdata
544                
545               $rr = Net::DNS::RR->new( type => NULL, rdata => 'arbitrary' );
546                
547               Resource record data section when viewed as opaque octets.
548                
549               =cut
550                
551               sub rdata {
552 173       173 1 2700 my $self = shift;
553                
554 173 100         764 return $self->_empty ? '' : eval { $self->_encode_rdata( 0x4000, {} ) } unless @_;
  116 100         483  
555                
556 34     100     99 my $data = shift || '';
557 34 100         177 $self->_decode_rdata( \$data, 0 ) if ( $self->{rdlength} = length $data );
558 32           61 return;
559               }
560                
561                
562               =head2 rdstring
563                
564               $rdstring = $rr->rdstring;
565                
566               Returns a string representation of the RR-specific data.
567                
568               =cut
569                
570               sub rdstring {
571 88       88 1 3252 my $self = shift;
572 88           262 local $SIG{__DIE__};
573                
574 88 100         211 my @rdata = $self->_empty ? () : eval { $self->_format_rdata };
  69           172  
575 88 100         327 carp $@ if $@;
576                
577 88           225 return join "\n\t", _wrap(@rdata);
578               }
579                
580                
581               =head2 rdlength
582                
583               $rdlength = $rr->rdlength;
584                
585               Returns the uncompressed length of the encoded RR-specific data.
586                
587               =cut
588                
589               sub rdlength {
590 7       7 1 60 return length shift->rdata;
591               }
592                
593                
594               ###################################################################################
595                
596               =head1 Sorting of RR arrays
597                
598               Sorting of RR arrays is done by Net::DNS::rrsort(), see documentation
599               for L. This package provides class methods to set the
600               comparator function used for a particular RR based on its attributes.
601                
602                
603               =head2 set_rrsort_func
604                
605               my $function = sub { ## numerically ascending order
606               $Net::DNS::a->{'preference'} <=> $Net::DNS::b->{'preference'};
607               };
608                
609               Net::DNS::RR::MX->set_rrsort_func( 'preference', $function );
610                
611               Net::DNS::RR::MX->set_rrsort_func( 'default_sort', $function );
612                
613               set_rrsort_func() must be called as a class method. The first argument is
614               the attribute name on which the sorting is to take place. If you specify
615               "default_sort" then that is the sort algorithm that will be used when
616               get_rrsort_func() is called without an RR attribute as argument.
617                
618               The second argument is a reference to a comparator function that uses the
619               global variables $a and $b in the Net::DNS package. During sorting, the
620               variables $a and $b will contain references to objects of the class whose
621               set_rrsort_func() was called. The above sorting function will only be
622               applied to Net::DNS::RR::MX objects.
623                
624               The above example is the sorting function implemented in MX.
625                
626               =cut
627                
628               our %rrsortfunct;
629                
630               sub set_rrsort_func {
631 42       42 1 92 my $class = shift;
632 42           69 my $attribute = shift;
633 42           61 my $function = shift;
634                
635 42           252 my ($type) = $class =~ m/::([^:]+)$/;
636 42           130 $rrsortfunct{$type}{$attribute} = $function;
637 42           96 return;
638               }
639                
640                
641               =head2 get_rrsort_func
642                
643               $function = Net::DNS::RR::MX->get_rrsort_func('preference');
644               $function = Net::DNS::RR::MX->get_rrsort_func();
645                
646               get_rrsort_func() returns a reference to the comparator function.
647                
648               =cut
649                
650               my $default = sub { return $Net::DNS::a->canonical() cmp $Net::DNS::b->canonical(); };
651                
652               sub get_rrsort_func {
653 13       13 1 1982 my $class = shift;
654 13     100     75 my $attribute = shift || 'default_sort';
655                
656 13           118 my ($type) = $class =~ m/::([^:]+)$/;
657                
658 13     100     68 return $rrsortfunct{$type}{$attribute} || return $default;
659               }
660                
661                
662               ################################################################################
663               #
664               # Net::DNS::RR->_subclass($rrname)
665               # Net::DNS::RR->_subclass($rrname, $default)
666               #
667               # Create a new object blessed into appropriate RR subclass, after
668               # loading the subclass module (if necessary). A subclass with no
669               # corresponding module will be regarded as unknown and blessed
670               # into the RR base class.
671               #
672               # The optional second argument indicates that default values are
673               # to be copied into the newly created object.
674                
675               our %_MINIMAL = ( 255 => bless ['type' => 255], __PACKAGE__ );
676               our %_LOADED = %_MINIMAL;
677                
678               sub _subclass {
679 11631       11631   16198 my ( $class, $rrname, $default ) = @_;
680                
681 11631 100         21501 unless ( $_LOADED{$rrname} ) {
682 184           810 my $rrtype = typebyname($rrname);
683                
684 183 100         668 unless ( $_LOADED{$rrtype} ) { # load once only
685 173           1045 local @INC = LIB;
686                
687 173           533 my $identifier = typebyval($rrtype);
688 173           544 $identifier =~ s/\W/_/g; # kosher Perl identifier
689                
690 173           552 my $subclass = join '::', __PACKAGE__, $identifier;
691                
692 173 100         12312 unless ( eval "require $subclass" ) { ## no critic ProhibitStringyEval
693 1           9 my $perl = Net::DNS::Parameters::_typespec("$rrtype.RRTYPE");
694 1           5 $subclass = join '::', __PACKAGE__, "TYPE$rrtype";
695               push @INC, sub { # see perldoc -f require
696 1       1   6 my @line = split /\n/, $perl;
697 1           81 return ( sub { defined( $_ = shift @line ) } );
  1           44  
698 1           8 };
699 1           70 eval "require $subclass"; ## no critic ProhibitStringyEval
700               }
701                
702 173 100         862 $subclass = __PACKAGE__ if $@;
703                
704               # cache pre-built minimal and populated default object images
705 173           613 my @base = ( 'type' => $rrtype );
706 173           964 $_MINIMAL{$rrtype} = bless [@base], $subclass;
707                
708 173           589 my $object = bless {@base}, $subclass;
709 173           1074 $object->_defaults;
710 173           1902 $_LOADED{$rrtype} = bless [%$object], $subclass;
711               }
712                
713 183           581 $_MINIMAL{$rrname} = $_MINIMAL{$rrtype};
714 183           381 $_LOADED{$rrname} = $_LOADED{$rrtype};
715               }
716                
717 11630 100         18729 my $prebuilt = $default ? $_LOADED{$rrname} : $_MINIMAL{$rrname};
718 11630           31549 return bless {@$prebuilt}, ref($prebuilt); # create object
719               }
720                
721                
722               sub _annotation {
723 1177       1177   6084 my ( $self, @note ) = @_;
724 1177 100         1948 push @{$self->{annotation}}, "\t; @note" if scalar @note;
  59           256  
725 1177 100         1706 return wantarray ? @{delete( $self->{annotation} ) || []} : undef;
  1118 100         3747  
726               }
727                
728                
729               my %warned;
730                
731               sub _deprecate {
732 9       9   18 my ( undef, @note ) = @_;
733 9 100         787 carp "deprecated method; @note" unless $warned{"@note"}++;
734 9           38 return;
735               }
736                
737                
738               my %ignore = map { ( $_ => 1 ) } @core, 'annotation', '#';
739                
740               sub _empty {
741 2802       2802   2910 my $self = shift;
742 2802     100     9007 return not( $self->{'#'} ||= scalar grep { !$ignore{$_} } keys %$self );
  8267           12810  
743               }
744                
745                
746               sub _wrap {
747 2367       2367   4445 my @text = @_;
748 2367           2423 my $cols = 80;
749 2367           2430 my $coln = 0;
750                
751 2367           2568 my ( @line, @fill );
752 2367           2901 foreach (@text) {
753 5627     100     7900 $coln += ( length || next ) + 1;
754 5591 100         7104 if ( $coln > $cols ) { # start new line
755 1779 100         3164 push( @line, join ' ', @fill ) if @fill;
756 1779           1733 $coln = length;
757 1779           1939 @fill = ();
758               }
759 5591 100         7646 $coln = $cols if chomp; # force line break
760 5591 100         8656 push( @fill, $_ ) if length;
761               }
762 2367           14181 return ( @line, join ' ', @fill );
763               }
764                
765                
766               ################################################################################
767                
768         1     sub DESTROY { } ## Avoid tickling AUTOLOAD (in cleanup)
769                
770               ## no critic
771               sub AUTOLOAD { ## Default method
772 11       11   52 my ($self) = @_;
773                
774 96       96   832 no strict 'refs'; ## no critic ProhibitNoStrict
  96           166  
  96           33580  
775 11           15 our $AUTOLOAD;
776 11           54 my ($method) = reverse split /::/, $AUTOLOAD;
777                
778 11           32 my $canonical = lc($method); ## tolerate mixed-case attribute name
779 11 100         72 if ( $self->can($canonical) ) {
780 6       25   55 *{$AUTOLOAD} = sub { shift->$canonical(@_) };
  6           36  
  25           2876  
781 6           20 return &$AUTOLOAD;
782               }
783                
784 5           8 my $oref = ref($self);
785 5       1   16 *{$AUTOLOAD} = sub { }; ## suppress deep recursion
  5           44  
786 5 100         156 croak qq[$self has no class method "$method"] unless $oref;
787                
788 4           13 my $string = $self->string;
789 4           37 my @object = grep { defined($_) } $oref, $oref->VERSION;
  8           16  
790 4           29 my $module = join '::', __PACKAGE__, $self->type;
791 4 100         61 eval("require $module") if $oref eq __PACKAGE__; ## no critic ProhibitStringyEval
792                
793 4           19 @_ = (<<"END");
794               *** FATAL PROGRAM ERROR!! Unknown instance method "$method"
795               *** which the program has attempted to call for the object:
796               ***
797               $string
798               ***
799               *** THIS IS A BUG IN THE CALLING SOFTWARE, which incorrectly assumes
800               *** that the object would be of a particular type. The type of an
801               *** object should be checked before calling any of its methods.
802               ***
803               @object
804               $@
805               END
806 4           1005 goto &Carp::confess;
807               }
808                
809                
810               1;
811               __END__