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   536151 use strict; use warnings;
  11     11   24  
  11         333  
  11         50  
  11         21  
  11         453  
6              
7             our $VERSION = '1.04';
8              
9 11     11   3917 use Net::Frame::Layer qw(:consts :subs);
  11         389506  
  11         2328  
10 11     11   75 use Exporter;
  11         16  
  11         1517  
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   54 use constant NF_DNS_QR_QUERY => 0;
  11         18  
  11         596  
52 11     11   48 use constant NF_DNS_QR_RESPONSE => 1;
  11         19  
  11         520  
53 11     11   49 use constant NF_DNS_OPCODE_QUERY => 0;
  11         19  
  11         406  
54 11     11   49 use constant NF_DNS_OPCODE_IQUERY => 1;
  11         24  
  11         439  
55 11     11   50 use constant NF_DNS_OPCODE_STATUS => 1;
  11         15  
  11         418  
56 11     11   133 use constant NF_DNS_OPCODE_NOTIFY => 4;
  11         24  
  11         466  
57 11     11   54 use constant NF_DNS_OPCODE_UPDATE => 5;
  11         14  
  11         464  
58 11     11   50 use constant NF_DNS_FLAGS_AA => 0x40;
  11         13  
  11         454  
59 11     11   54 use constant NF_DNS_FLAGS_TC => 0x20;
  11         61  
  11         467  
60 11     11   59 use constant NF_DNS_FLAGS_RD => 0x10;
  11         15  
  11         409  
61 11     11   49 use constant NF_DNS_FLAGS_RA => 0x08;
  11         21  
  11         406  
62 11     11   46 use constant NF_DNS_FLAGS_Z => 0x04;
  11         18  
  11         471  
63 11     11   59 use constant NF_DNS_FLAGS_AD => 0x02;
  11         36  
  11         437  
64 11     11   59 use constant NF_DNS_FLAGS_CD => 0x01;
  11         37  
  11         475  
65 11     11   48 use constant NF_DNS_RCODE_NOERROR => 0;
  11         22  
  11         434  
66 11     11   52 use constant NF_DNS_RCODE_FORMATERROR => 1;
  11         22  
  11         607  
67 11     11   49 use constant NF_DNS_RCODE_SERVERFAILURE => 2;
  11         24  
  11         410  
68 11     11   48 use constant NF_DNS_RCODE_NAMEERROR => 3;
  11         36  
  11         486  
69 11     11   48 use constant NF_DNS_RCODE_NOTIMPLEMENTED => 4;
  11         17  
  11         401  
70 11     11   48 use constant NF_DNS_RCODE_REFUSED => 5;
  11         16  
  11         444  
71 11     11   44 use constant NF_DNS_RCODE_YXDOMAIN => 6;
  11         19  
  11         409  
72 11     11   44 use constant NF_DNS_RCODE_YXRRSET => 7;
  11         24  
  11         418  
73 11     11   57 use constant NF_DNS_RCODE_NXRRSET => 8;
  11         30  
  11         451  
74 11     11   49 use constant NF_DNS_RCODE_NOTAUTH => 9;
  11         18  
  11         411  
75 11     11   51 use constant NF_DNS_RCODE_NOTZONE => 10;
  11         18  
  11         1022  
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   8090 use Bit::Vector;
  11         11120  
  11         571  
94 11     11   5819 use Net::Frame::Layer::DNS::Constants qw(:consts);
  11         26  
  11         20163  
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 6941 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 391 my $self = shift;
138              
139 1         6 my $qr = Bit::Vector->new_Dec(1, $self->qr);
140 1         54 my $opcode = Bit::Vector->new_Dec(4, $self->opcode);
141 1         16 my $flags = Bit::Vector->new_Dec(7, $self->flags);
142 1         15 my $rcode = Bit::Vector->new_Dec(4, $self->rcode);
143 1         24 my $bvlist = $qr->Concat_List($opcode, $flags, $rcode);
144              
145 1 50       6 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         71 return $self->raw($raw);
155             }
156              
157             sub unpack {
158 1     1 1 21 my $self = shift;
159              
160 1         3 $dns_payload = $self->raw;
161              
162 1 50       13 my ($id, $bv, $qdCount, $anCount, $nsCount, $arCount, $payload) =
163             $self->SUPER::unpack('nnnnnn a*', $self->raw)
164             or return;
165              
166 1         30 $self->id($id);
167              
168 1         14 my $bvlist = Bit::Vector->new_Dec(16, $bv);
169 1         12 $self->qr ($bvlist->Chunk_Read(1,15));
170 1         12 $self->opcode($bvlist->Chunk_Read(4,11));
171 1         12 $self->flags ($bvlist->Chunk_Read(7, 4));
172 1         12 $self->rcode ($bvlist->Chunk_Read(4, 0));
173              
174 1         10 $self->qdCount($qdCount);
175 1         10 $self->anCount($anCount);
176 1         10 $self->nsCount($nsCount);
177 1         23 $self->arCount($arCount);
178              
179 1         14 $self->payload($payload);
180              
181 1         13 return $self;
182             }
183              
184             sub encapsulate {
185 1     1 1 6 my $self = shift;
186              
187 1 50       8 return $self->nextLayer if $self->nextLayer;
188              
189 1 50       17 if ($self->payload) {
190 0         0 return 'DNS::Question';
191             }
192              
193 1         14 NF_LAYER_NONE;
194             }
195              
196             sub print {
197 1     1 1 4 my $self = shift;
198              
199 1         7 my $l = $self->layer;
200 1         23 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         536 return $buf;
209             }
210              
211             ####
212              
213             sub dnsAton {
214 16     16 1 276 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         22 my $name = '';
223 16         56 my @parts = split /\./, $self;
224 16         31 for my $part (@parts) {
225 17         106 $name .= sprintf "%.2x%s", length($part), CORE::unpack "H*", $part
226             }
227 16         40 $name .= CORE::unpack "H*", "\0";
228 16         52 return $name
229             }
230              
231             sub dnsNtoa {
232 2     2 1 11 my $self = shift;
233              
234 2         6 my $name = '';
235 2         4 my $start = 0;
236 2         4 my $i;
237 2         13 for ($i = 0; $i < length($self); $i++) {
238             # start counts down the letters in section (originally separate by '.')
239 11 100       19 if ($start == 0) {
240 2         5 $start = hex (CORE::unpack "H*", (substr $self, $i, 1));
241             # If null, done name
242 2 100       6 if ($start == 0) {
243 1         1 $i+=1;
244             last
245 1         2 }
246             # if pointer, done name ...
247 1 50       4 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       4 if ($name ne '') {
265 0         0 $name .= '.'
266             }
267             next
268 1         3 }
269 9         14 my $t = hex (CORE::unpack "H*", (substr $self, $i, 1));
270             # If null, done name
271 9 50       15 if ($t == 0) {
272 0         0 $i+=1;
273             last
274 0         0 }
275             # If pointer, done name ...
276 9 50       13 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         11 $name .= substr $self, $i, 1;
294 9         14 $start--
295             }
296              
297 2         8 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__