File Coverage

blib/lib/Net/DNS/DomainName.pm
Criterion Covered Total %
statement 64 64 100.0
branch 18 18 100.0
path n/a
condition 10 11 100.0
subroutine 10 10 100.0
pod 3 3 100.0
total 105 106 100.0


line stmt bran path cond sub pod time code
1               package Net::DNS::DomainName;
2                
3 99       99   236539 use strict;
  99           179  
  99           3233  
4 99       99   349 use warnings;
  99           128  
  99           6996  
5                
6               our $VERSION = (qw$Id: DomainName.pm 2005 2025-01-28 13:22:10Z willem $)[2];
7                
8                
9               =head1 NAME
10                
11               Net::DNS::DomainName - DNS name representation
12                
13               =head1 SYNOPSIS
14                
15               use Net::DNS::DomainName;
16                
17               $object = Net::DNS::DomainName->new('example.com');
18               $name = $object->name;
19               $data = $object->encode;
20                
21               ( $object, $next ) = Net::DNS::DomainName->decode( \$data, $offset );
22                
23               =head1 DESCRIPTION
24                
25               The Net::DNS::DomainName module implements the concrete representation
26               of DNS domain names used within DNS packets.
27                
28               Net::DNS::DomainName defines methods for encoding and decoding wire
29               format octet strings. All other behaviour is inherited from
30               Net::DNS::Domain.
31                
32               The Net::DNS::DomainName1035 and Net::DNS::DomainName2535 packages
33               implement disjoint domain name subtypes which provide the name
34               compression and canonicalisation specified by RFC1035 and RFC2535.
35               These are necessary to meet the backward compatibility requirements
36               introduced by RFC3597.
37                
38               =cut
39                
40                
41 99       99   458 use base qw(Net::DNS::Domain);
  99           142  
  99           41232  
42                
43 99       99   637 use integer;
  99           149  
  99           628  
44 99       99   2782 use Carp;
  99           158  
  99           71936  
45                
46                
47               =head1 METHODS
48                
49               =head2 new
50                
51               $object = Net::DNS::DomainName->new('example.com');
52                
53               Creates a domain name object which identifies the domain specified
54               by the character string argument.
55                
56                
57               =head2 decode
58                
59               $object = Net::DNS::DomainName->decode( \$buffer, $offset, $hash );
60                
61               ( $object, $next ) = Net::DNS::DomainName->decode( \$buffer, $offset, $hash );
62                
63               Creates a domain name object which represents the DNS domain name
64               identified by the wire-format data at the indicated offset within
65               the data buffer.
66                
67               The argument list consists of a reference to a scalar containing the
68               wire-format data and specified offset. The optional reference to a
69               hash table provides improved efficiency of decoding compressed names
70               by exploiting already cached compression pointers.
71                
72               The returned offset value indicates the start of the next item in the
73               data buffer.
74                
75               =cut
76                
77               sub decode {
78 11242       11242 1 17430 my $label = [];
79 11242           20521 my $self = bless {label => $label}, shift;
80 11242           12965 my $buffer = shift; # reference to data buffer
81 11242     100     16423 my $offset = shift || 0; # offset within buffer
82 11242           10943 my $linked = shift; # caller's compression index
83 11242           11866 my $cache = $linked;
84 11242           22155 $cache->{$offset} = $self; # hashed objectref by offset
85                
86 11242           11899 my $buflen = length $$buffer;
87 11242           12043 my $index = $offset;
88                
89 11242           15236 while ( $index < $buflen ) {
90 14692     100     30562 my $header = unpack( "\@$index C", $$buffer )
91               || return wantarray ? ( $self, ++$index ) : $self;
92                
93 13338 100         20722 if ( $header < 0x40 ) { # non-terminal label
    100            
94 3465           6668 push @$label, substr( $$buffer, ++$index, $header );
95 3465           5418 $index += $header;
96                
97               } elsif ( $header < 0xC0 ) { # deprecated extended label types
98 2           175 croak 'unimplemented label type';
99                
100               } else { # compression pointer
101 9871           14329 my $link = 0x3FFF & unpack( "\@$index n", $$buffer );
102 9871 100         14464 croak 'corrupt compression pointer' unless $link < $offset;
103 9870 100         12793 croak 'invalid compression pointer' unless $linked;
104                
105               # uncoverable condition false
106 9869     66     18597 $self->{origin} = $cache->{$link} ||= __PACKAGE__->decode( $buffer, $link, $cache );
107 9869 100         23165 return wantarray ? ( $self, $index + 2 ) : $self;
108               }
109               }
110 15           1735 croak 'corrupt wire-format data';
111               }
112                
113                
114               =head2 encode
115                
116               $data = $object->encode;
117                
118               Returns the wire-format representation of the domain name suitable
119               for inclusion in a DNS packet buffer.
120                
121               =cut
122                
123               sub encode {
124 142       142 1 1571 return join '', map { pack 'C a*', length($_), $_ } shift->_wire, '';
  444           1361  
125               }
126                
127                
128               =head2 canonical
129                
130               $data = $object->canonical;
131                
132               Returns the canonical wire-format representation of the domain name
133               as defined in RFC2535(8.1).
134                
135               =cut
136                
137               sub canonical {
138 932       932 1 1938 my @label = shift->_wire;
139 932           1348 for (@label) {
140 2194           2788 tr /\101-\132/\141-\172/;
141               }
142 932           1231 return join '', map { pack 'C a*', length($_), $_ } @label, '';
  3126           7290  
143               }
144                
145                
146               ########################################
147                
148               package Net::DNS::DomainName1035; ## no critic ProhibitMultiplePackages
149               our @ISA = qw(Net::DNS::DomainName);
150                
151               =head1 Net::DNS::DomainName1035
152                
153               Net::DNS::DomainName1035 implements a subclass of domain name
154               objects which are to be encoded using the compressed wire format
155               defined in RFC1035.
156                
157               $data = $object->encode( $offset, $hash );
158                
159               The arguments are the offset within the packet data where
160               the domain name is to be stored and a reference to a hash table used
161               to index compressed names within the packet.
162                
163               Note that RFC3597 implies that only the RR types defined in RFC1035(3.3)
164               are eligible for compression of domain names occuring in RDATA.
165                
166               If the hash reference is undefined, encode() returns the lower case
167               uncompressed canonical representation defined in RFC2535(8.1).
168                
169               =cut
170                
171               sub encode {
172 1512       1512   1767 my $self = shift;
173 1512     100     2961 my $offset = shift || 0; # offset in data buffer
174 1512     100     2519 my $hash = shift || return $self->canonical; # hashed offset by name
175                
176 1408           2827 my @labels = $self->_wire;
177 1408           2533 my $data = '';
178 1408           2170 while (@labels) {
179 2343           3601 my $name = join( '.', @labels );
180                
181 2343 100         4582 return $data . pack( 'n', 0xC000 | $hash->{$name} ) if defined $hash->{$name};
182                
183 1785           2457 my $label = shift @labels;
184 1785           2204 my $length = length $label;
185 1785           3201 $data .= pack( 'C a*', $length, $label );
186                
187 1785 100         3263 next unless $offset < 0x4000;
188 752           1355 $hash->{$name} = $offset;
189 752           1244 $offset += 1 + $length;
190               }
191 850           1958 return $data .= pack 'x';
192               }
193                
194                
195               ########################################
196                
197               package Net::DNS::DomainName2535; ## no critic ProhibitMultiplePackages
198               our @ISA = qw(Net::DNS::DomainName);
199                
200               =head1 Net::DNS::DomainName2535
201                
202               Net::DNS::DomainName2535 implements a subclass of domain name
203               objects which are to be encoded using uncompressed wire format.
204                
205               $data = $object->encode( $offset, $hash );
206                
207               The arguments are the offset within the packet data where
208               the domain name is to be stored and a reference to a hash table used
209               to index names already encoded within the packet.
210                
211               If the hash reference is undefined, encode() returns the lower case
212               uncompressed canonical representation defined in RFC2535(8.1).
213                
214               Note that RFC3597, and latterly RFC4034, specifies that the lower case
215               canonical form is to be used for RR types defined prior to RFC3597.
216                
217               =cut
218                
219               sub encode {
220 114       114   262 my ( $self, $offset, $hash ) = @_;
221 114 100         342 return $self->canonical unless defined $hash;
222 56           160 my $name = join '.', my @labels = $self->_wire;
223 56 100         110 $hash->{$name} = $offset if $offset < 0x4000;
224 56           84 return join '', map { pack 'C a*', length($_), $_ } @labels, '';
  196           467  
225               }
226                
227               1;
228               __END__