File Coverage

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


line stmt bran cond sub pod time code
1             package Net::DNS::DomainName;
2              
3 99     99   339948 use strict;
  99         227  
  99         4149  
4 99     99   604 use warnings;
  99         169  
  99         9367  
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   645 use base qw(Net::DNS::Domain);
  99         186  
  99         52536  
42              
43 99     99   3201 use integer;
  99         190  
  99         793  
44 99     99   4049 use Carp;
  99         238  
  99         96714  
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 10591     10591 1 33879 my $label = [];
79 10591         28587 my $self = bless {label => $label}, shift;
80 10591         16546 my $buffer = shift; # reference to data buffer
81 10591   100     23791 my $offset = shift || 0; # offset within buffer
82 10591         15905 my $linked = shift; # caller's compression index
83 10591         15092 my $cache = $linked;
84 10591         28922 $cache->{$offset} = $self; # hashed objectref by offset
85              
86 10591         17941 my $buflen = length $$buffer;
87 10591         16191 my $index = $offset;
88              
89 10591         24750 while ( $index < $buflen ) {
90 14106   100     45652 my $header = unpack( "\@$index C", $$buffer )
91             || return wantarray ? ( $self, ++$index ) : $self;
92              
93 12727 100       28996 if ( $header < 0x40 ) { # non-terminal label
    100          
94 3530         10176 push @$label, substr( $$buffer, ++$index, $header );
95 3530         8227 $index += $header;
96              
97             } elsif ( $header < 0xC0 ) { # deprecated extended label types
98 2         219 croak 'unimplemented label type';
99              
100             } else { # compression pointer
101 9195         19176 my $link = 0x3FFF & unpack( "\@$index n", $$buffer );
102 9195 100       17453 croak 'corrupt compression pointer' unless $link < $offset;
103 9194 100       16103 croak 'invalid compression pointer' unless $linked;
104              
105             # uncoverable condition false
106 9193   66     24125 $self->{origin} = $cache->{$link} ||= __PACKAGE__->decode( $buffer, $link, $cache );
107 9193 100       31989 return wantarray ? ( $self, $index + 2 ) : $self;
108             }
109             }
110 15         2584 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 1624 return join '', map { pack 'C a*', length($_), $_ } shift->_wire, '';
  444         1664  
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 2357 my @label = shift->_wire;
139 932         1722 for (@label) {
140 2194         3834 tr /\101-\132/\141-\172/;
141             }
142 932         1731 return join '', map { pack 'C a*', length($_), $_ } @label, '';
  3126         9887  
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   2451 my $self = shift;
173 1512   100     3633 my $offset = shift || 0; # offset in data buffer
174 1512   100     3279 my $hash = shift || return $self->canonical; # hashed offset by name
175              
176 1408         4012 my @labels = $self->_wire;
177 1408         3061 my $data = '';
178 1408         3136 while (@labels) {
179 2346         8490 my $name = join( '.', @labels );
180              
181 2346 100       6899 return $data . pack( 'n', 0xC000 | $hash->{$name} ) if defined $hash->{$name};
182              
183 1788         3268 my $label = shift @labels;
184 1788         3107 my $length = length $label;
185 1788         4790 $data .= pack( 'C a*', $length, $label );
186              
187 1788 100       4816 next unless $offset < 0x4000;
188 755         1837 $hash->{$name} = $offset;
189 755         2943 $offset += 1 + $length;
190             }
191 850         2763 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   202 my ( $self, $offset, $hash ) = @_;
221 114 100       220 return $self->canonical unless defined $hash;
222 56         141 my $name = join '.', my @labels = $self->_wire;
223 56 100       131 $hash->{$name} = $offset if $offset < 0x4000;
224 56         109 return join '', map { pack 'C a*', length($_), $_ } @labels, '';
  196         658  
225             }
226              
227             1;
228             __END__