File Coverage

blib/lib/Net/Frame/Layer/DNS.pm
Criterion Covered Total %
statement 151 192 78.6
branch 12 32 37.5
condition 0 6 0.0
subroutine 38 43 88.3
pod 11 11 100.0
total 212 284 74.6


line stmt bran cond sub pod time code
1             #
2             # $Id: DNS.pm 49 2013-03-04 13:15:34Z VinsWorldcom $
3             #
4             package Net::Frame::Layer::DNS;
5 11     11   333816 use strict; use warnings;
  11     11   30  
  11         251  
  11         49  
  11         24  
  11         396  
6              
7             our $VERSION = '1.05';
8              
9 11     11   1723 use Net::Frame::Layer qw(:consts :subs);
  11         201882  
  11         1661  
10 11     11   81 use Exporter;
  11         24  
  11         1135  
11             our @ISA = qw(Net::Frame::Layer Exporter);
12              
13             our %EXPORT_TAGS = (
14             consts => [qw(
15             NF_DNS_QR_QUERY
16             NF_DNS_QR_RESPONSE
17             NF_DNS_OPCODE_QUERY
18             NF_DNS_OPCODE_IQUERY
19             NF_DNS_OPCODE_STATUS
20             NF_DNS_OPCODE_NOTIFY
21             NF_DNS_OPCODE_UPDATE
22             NF_DNS_FLAGS_AA
23             NF_DNS_FLAGS_TC
24             NF_DNS_FLAGS_RD
25             NF_DNS_FLAGS_RA
26             NF_DNS_FLAGS_Z
27             NF_DNS_FLAGS_AD
28             NF_DNS_FLAGS_CD
29             NF_DNS_RCODE_NOERROR
30             NF_DNS_RCODE_FORMATERROR
31             NF_DNS_RCODE_SERVERFAILURE
32             NF_DNS_RCODE_NAMEERROR
33             NF_DNS_RCODE_NOTIMPLEMENTED
34             NF_DNS_RCODE_REFUSED
35             NF_DNS_RCODE_YXDOMAIN
36             NF_DNS_RCODE_YXRRSET
37             NF_DNS_RCODE_NXRRSET
38             NF_DNS_RCODE_NOTAUTH
39             NF_DNS_RCODE_NOTZONE
40             )],
41             subs => [qw(
42             dnsAton
43             dnsNtoa
44             )],
45             );
46             our @EXPORT_OK = (
47             @{$EXPORT_TAGS{consts}},
48             @{$EXPORT_TAGS{subs}},
49             );
50              
51 11     11   72 use constant NF_DNS_QR_QUERY => 0;
  11         23  
  11         561  
52 11     11   59 use constant NF_DNS_QR_RESPONSE => 1;
  11         23  
  11         401  
53 11     11   54 use constant NF_DNS_OPCODE_QUERY => 0;
  11         21  
  11         369  
54 11     11   53 use constant NF_DNS_OPCODE_IQUERY => 1;
  11         64  
  11         375  
55 11     11   51 use constant NF_DNS_OPCODE_STATUS => 1;
  11         21  
  11         421  
56 11     11   79 use constant NF_DNS_OPCODE_NOTIFY => 4;
  11         28  
  11         382  
57 11     11   53 use constant NF_DNS_OPCODE_UPDATE => 5;
  11         21  
  11         428  
58 11     11   53 use constant NF_DNS_FLAGS_AA => 0x40;
  11         24  
  11         378  
59 11     11   48 use constant NF_DNS_FLAGS_TC => 0x20;
  11         20  
  11         345  
60 11     11   54 use constant NF_DNS_FLAGS_RD => 0x10;
  11         21  
  11         418  
61 11     11   53 use constant NF_DNS_FLAGS_RA => 0x08;
  11         22  
  11         353  
62 11     11   52 use constant NF_DNS_FLAGS_Z => 0x04;
  11         19  
  11         467  
63 11     11   55 use constant NF_DNS_FLAGS_AD => 0x02;
  11         18  
  11         352  
64 11     11   49 use constant NF_DNS_FLAGS_CD => 0x01;
  11         24  
  11         343  
65 11     11   53 use constant NF_DNS_RCODE_NOERROR => 0;
  11         20  
  11         369  
66 11     11   48 use constant NF_DNS_RCODE_FORMATERROR => 1;
  11         20  
  11         352  
67 11     11   50 use constant NF_DNS_RCODE_SERVERFAILURE => 2;
  11         21  
  11         402  
68 11     11   60 use constant NF_DNS_RCODE_NAMEERROR => 3;
  11         17  
  11         372  
69 11     11   52 use constant NF_DNS_RCODE_NOTIMPLEMENTED => 4;
  11         21  
  11         347  
70 11     11   53 use constant NF_DNS_RCODE_REFUSED => 5;
  11         23  
  11         380  
71 11     11   52 use constant NF_DNS_RCODE_YXDOMAIN => 6;
  11         21  
  11         359  
72 11     11   48 use constant NF_DNS_RCODE_YXRRSET => 7;
  11         20  
  11         349  
73 11     11   47 use constant NF_DNS_RCODE_NXRRSET => 8;
  11         24  
  11         397  
74 11     11   52 use constant NF_DNS_RCODE_NOTAUTH => 9;
  11         21  
  11         367  
75 11     11   56 use constant NF_DNS_RCODE_NOTZONE => 10;
  11         21  
  11         872  
76              
77             our @AS = qw(
78             id
79             qr
80             opcode
81             flags
82             rcode
83             qdCount
84             anCount
85             nsCount
86             arCount
87             );
88             __PACKAGE__->cgBuildIndices;
89             __PACKAGE__->cgBuildAccessorsScalar(\@AS);
90              
91             #no strict 'vars';
92              
93 11     11   2313 use Bit::Vector;
  11         4553  
  11         405  
94 11     11   3280 use Net::Frame::Layer::DNS::Constants qw(:consts);
  11         75  
  11         12108  
95              
96             my $dns_payload;
97              
98             $Net::Frame::Layer::UDP::Next->{53} = "DNS";
99              
100             sub new {
101             shift->SUPER::new(
102 6     6 1 5598 id => getRandom16bitsInt(),
103             qr => NF_DNS_QR_QUERY,
104             opcode => NF_DNS_OPCODE_QUERY,
105             flags => NF_DNS_FLAGS_RD,
106             rcode => NF_DNS_RCODE_NOERROR,
107             qdCount => 1,
108             anCount => 0,
109             nsCount => 0,
110             arCount => 0,
111             @_,
112             );
113             }
114              
115             sub match {
116 0     0 1 0 my $self = shift;
117 0         0 my ($with) = @_;
118 0         0 my $sQr = $self->qr;
119 0         0 my $sId = $self->id;
120 0         0 my $wQr = $with->qr;
121 0         0 my $wId = $with->id;
122 0 0 0     0 if (($sQr == NF_DNS_QR_QUERY)
      0        
123             && ($wQr == NF_DNS_QR_RESPONSE)
124             && ($sId == $wId)) {
125 0         0 return 1;
126             }
127 0         0 0;
128             }
129              
130             # XXX: may be better, by keying on type also
131 0     0 1 0 sub getKey { shift->layer }
132 0     0 1 0 sub getKeyReverse { shift->layer }
133              
134 0     0 1 0 sub getLength { 12 }
135              
136             sub pack {
137 1     1 1 414 my $self = shift;
138              
139 1         4 my $qr = Bit::Vector->new_Dec(1, $self->qr);
140 1         40 my $opcode = Bit::Vector->new_Dec(4, $self->opcode);
141 1         14 my $flags = Bit::Vector->new_Dec(7, $self->flags);
142 1         12 my $rcode = Bit::Vector->new_Dec(4, $self->rcode);
143 1         18 my $bvlist = $qr->Concat_List($opcode, $flags, $rcode);
144              
145 1 50       4 my $raw = $self->SUPER::pack('nnnnnn',
146             $self->id,
147             $bvlist->to_Dec,
148             $self->qdCount,
149             $self->anCount,
150             $self->nsCount,
151             $self->arCount
152             ) or return;
153              
154 1         69 return $self->raw($raw);
155             }
156              
157             sub unpack {
158 1     1 1 22 my $self = shift;
159              
160 1         3 $dns_payload = $self->raw;
161              
162 1 50       11 my ($id, $bv, $qdCount, $anCount, $nsCount, $arCount, $payload) =
163             $self->SUPER::unpack('nnnnnn a*', $self->raw)
164             or return;
165              
166 1         34 $self->id($id);
167              
168 1         12 my $bvlist = Bit::Vector->new_Dec(16, $bv);
169 1         9 $self->qr ($bvlist->Chunk_Read(1,15));
170 1         13 $self->opcode($bvlist->Chunk_Read(4,11));
171 1         11 $self->flags ($bvlist->Chunk_Read(7, 4));
172 1         12 $self->rcode ($bvlist->Chunk_Read(4, 0));
173              
174 1         9 $self->qdCount($qdCount);
175 1         10 $self->anCount($anCount);
176 1         10 $self->nsCount($nsCount);
177 1         9 $self->arCount($arCount);
178              
179 1         14 $self->payload($payload);
180              
181 1         11 return $self;
182             }
183              
184             sub encapsulate {
185 1     1 1 5 my $self = shift;
186              
187 1 50       6 return $self->nextLayer if $self->nextLayer;
188              
189 1 50       16 if ($self->payload) {
190 0         0 return 'DNS::Question';
191             }
192              
193 1         12 NF_LAYER_NONE;
194             }
195              
196             sub print {
197 1     1 1 5 my $self = shift;
198              
199 1         5 my $l = $self->layer;
200 1         27 my $buf = sprintf
201             "$l: id:%d qr:%d opcode:%d flags:0x%02x rcode:%d\n".
202             "$l: qdCount:%d anCount:%d\n".
203             "$l: nsCount:%d arCount:%d",
204             $self->id, $self->qr, $self->opcode, $self->flags, $self->rcode,
205             $self->qdCount, $self->anCount,
206             $self->nsCount, $self->arCount;
207              
208 1         102 return $buf;
209             }
210              
211             ####
212              
213             sub dnsAton {
214 16     16 1 236 my $self = shift;
215              
216             # Weird pack routine. Queries are encoded by:
217             # ...
218             # For example:
219             # 3www6google3com\0
220             # 0377777706676f6f676c6503636f6d00
221             # 3 w w w 6 g o o g l e 3 c o m\0
222 16         31 my $name = '';
223 16         51 my @parts = split /\./, $self;
224 16         37 for my $part (@parts) {
225 17         93 $name .= sprintf "%.2x%s", length($part), CORE::unpack "H*", $part
226             }
227 16         39 $name .= CORE::unpack "H*", "\0";
228 16         49 return $name
229             }
230              
231             sub dnsNtoa {
232 2     2 1 16 my $self = shift;
233              
234 2         5 my $name = '';
235 2         4 my $start = 0;
236 2         5 my $i;
237 2         11 for ($i = 0; $i < length($self); $i++) {
238             # start counts down the letters in section (originally separate by '.')
239 11 100       25 if ($start == 0) {
240 2         6 $start = hex (CORE::unpack "H*", (substr $self, $i, 1));
241             # If null, done name
242 2 100       7 if ($start == 0) {
243 1         2 $i+=1;
244             last
245 1         2 }
246             # if pointer, done name ...
247 1 50       5 if (($start & 0xc0) == 0xc0) {
248             # get pointer position
249 0         0 my $ptr = hex (CORE::unpack "H*", (substr $self, $i+1, 1));
250 0 0       0 if ($name ne '') { $name .= "." }
  0         0  
251 0         0 $name .= "[@" . $ptr . "(";
252 0         0 $i+=2;
253             # resolve pointer if possible
254 0 0       0 if (defined($ptr = _getptr($ptr))) {
255 0         0 $name .= $ptr
256             } else {
257 0         0 $name .= "!ERROR!"
258             }
259 0         0 $name .= ")]";
260             # done
261             last
262 0         0 }
263             # add . to name to separate
264 1 50       3 if ($name ne '') {
265 0         0 $name .= '.'
266             }
267             next
268 1         3 }
269 9         20 my $t = hex (CORE::unpack "H*", (substr $self, $i, 1));
270             # If null, done name
271 9 50       26 if ($t == 0) {
272 0         0 $i+=1;
273             last
274 0         0 }
275             # If pointer, done name ...
276 9 50       20 if (($t & 0xc0) == 0xc0) {
277             # get pointer position
278 0         0 my $ptr = hex (CORE::unpack "H*", (substr $self, $i+1, 1));
279 0 0       0 if ($name ne '') { $name .= "." }
  0         0  
280 0         0 $name .= "[@" . $ptr . "(";
281 0         0 $i+=2;
282             # resolve pointer if possible
283 0 0       0 if (defined($ptr = _getptr($ptr))) {
284 0         0 $name .= $ptr
285             } else {
286 0         0 $name .= "!ERROR!"
287             }
288 0         0 $name .= ")]";
289             # done
290             last
291 0         0 }
292             # add next letter to name
293 9         13 $name .= substr $self, $i, 1;
294 9         19 $start--
295             }
296              
297 2         7 return ($name, $i)
298             }
299              
300             sub _getptr {
301 0     0     my $ptr = shift;
302              
303 0 0         if (defined($dns_payload)) {
304 0           my ($name) = dnsNtoa(substr $dns_payload, $ptr);
305 0           return $name
306             }
307             return undef
308 0           }
309              
310             1;
311              
312             __END__