File Coverage

blib/lib/Net/Packet/Frame.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             #
2             # $Id: Frame.pm 2002 2015-02-15 16:50:35Z gomor $
3             #
4             package Net::Packet::Frame;
5 1     1   4404 use warnings;
  1         2  
  1         29  
6 1     1   4 use strict;
  1         0  
  1         23  
7 1     1   3 use Carp;
  1         3  
  1         203  
8              
9             require Class::Gomor::Array;
10             our @ISA = qw(Class::Gomor::Array);
11              
12             require Net::Packet::Dump;
13             require Net::Packet::ETH;
14             require Net::Packet::ARP;
15             require Net::Packet::IPv4;
16             require Net::Packet::IPv6;
17             require Net::Packet::TCP;
18             require Net::Packet::UDP;
19             require Net::Packet::ICMPv4;
20             require Net::Packet::Layer7;
21             require Net::Packet::NULL;
22             require Net::Packet::PPPoE;
23             require Net::Packet::PPP;
24             require Net::Packet::LLC;
25             require Net::Packet::PPPLCP;
26             require Net::Packet::CDP;
27             require Net::Packet::STP;
28             require Net::Packet::OSPF;
29             require Net::Packet::IGMPv4;
30             require Net::Packet::RAW;
31             require Net::Packet::SLL;
32             require Net::Packet::VLAN;
33              
34 1     1   1311 use Time::HiRes qw(gettimeofday);
  1         1326  
  1         3  
35 1     1   528 use Net::Packet::Env qw($Env);
  0            
  0            
36             use Net::Packet::Consts qw(:dump :layer :arp);
37              
38             our @AS = qw(
39             env
40             raw
41             l2
42             l3
43             l4
44             l7
45             reply
46             timestamp
47             encapsulate
48             padding
49             );
50             __PACKAGE__->cgBuildIndices;
51             __PACKAGE__->cgBuildAccessorsScalar(\@AS);
52              
53             no strict 'vars';
54              
55             sub _gettimeofday {
56             my ($sec, $usec) = gettimeofday();
57             sprintf("%d.%06d", $sec, $usec);
58             }
59              
60             sub new {
61             my $self = shift->SUPER::new(
62             timestamp => _gettimeofday(),
63             env => $Env,
64             encapsulate => NP_LAYER_UNKNOWN,
65             @_,
66             );
67              
68             my $env = $self->[$__env];
69              
70             if (! $env->noFrameAutoDesc && ! $env->desc) {
71             if ($self->[$__l2]) {
72             require Net::Packet::DescL2;
73             $env->desc(Net::Packet::DescL2->new);
74             $self->cgDebugPrint(1, "DescL2 object created");
75             }
76             elsif ($self->[$__l3]) {
77             require Net::Packet::DescL3;
78             $env->desc(Net::Packet::DescL3->new(
79             target => $self->[$__l3]->dst,
80             ));
81             $self->cgDebugPrint(1, "DescL3 object created");
82             }
83             elsif ($self->[$__l4]) {
84             confess("@{[(caller(0))[3]]}: you must manually create a DescL4 ".
85             "object\n");
86             }
87             }
88              
89             if (! $env->noFrameAutoDump && ! $env->dump) {
90             my $getFilter;
91             my $dumpFilter = ($env->dump && $env->dump->filter);
92             if ($dumpFilter || ($getFilter = $self->getFilter)) {
93             require Net::Packet::Dump;
94             $env->dump(
95             Net::Packet::Dump->new(
96             filter => $dumpFilter || $getFilter,
97             ),
98             );
99             $self->cgDebugPrint(1, "Dump object created");
100             }
101             }
102              
103             $self->[$__raw] ? $self->unpack : $self->pack;
104             }
105              
106             sub getLengthFromL7 {
107             my $self = shift;
108             $self->[$__l7] ? $self->[$__l7]->getLength : 0;
109             }
110             sub getLengthFromL4 {
111             my $self = shift;
112             my $len = 0;
113             $len += $self->[$__l4]->getLength if $self->[$__l4];
114             $len += $self->getLengthFromL7;
115             $len || 0;
116             }
117             sub getLengthFromL3 {
118             my $self = shift;
119             my $len = 0;
120             $len += $self->[$__l3]->getLength if $self->[$__l3];
121             $len += $self->getLengthFromL4;
122             $len || 0;
123             }
124             sub getLengthFromL2 {
125             my $self = shift;
126             my $len = 0;
127             $len += $self->[$__l2]->getLength if $self->[$__l2];
128             $len += $self->getLengthFromL3;
129             $len || 0;
130             }
131             sub getLength { shift->getLengthFromL3 }
132              
133             my $whichLink = {
134             NP_LAYER_ETH() =>
135             sub { Net::Packet::ETH->new(raw => shift()) },
136             NP_LAYER_NULL() =>
137             sub { Net::Packet::NULL->new(raw => shift()) },
138             NP_LAYER_RAW() =>
139             sub { Net::Packet::RAW->new(raw => shift()) },
140             NP_LAYER_SLL() =>
141             sub { Net::Packet::SLL->new(raw => shift()) },
142             NP_LAYER_ARP() =>
143             sub { Net::Packet::ARP->new(raw => shift()) },
144             NP_LAYER_IPv4() =>
145             sub { Net::Packet::IPv4->new(raw => shift()) },
146             NP_LAYER_IPv6() =>
147             sub { Net::Packet::IPv6->new(raw => shift()) },
148             NP_LAYER_VLAN() =>
149             sub { Net::Packet::VLAN->new(raw => shift()) },
150             NP_LAYER_TCP() =>
151             sub { Net::Packet::TCP->new(raw => shift()) },
152             NP_LAYER_UDP() =>
153             sub { Net::Packet::UDP->new(raw => shift()) },
154             NP_LAYER_ICMPv4() =>
155             sub { Net::Packet::ICMPv4->new(raw => shift()) },
156             NP_LAYER_PPPoE() =>
157             sub { Net::Packet::PPPoE->new(raw => shift()) },
158             NP_LAYER_PPP() =>
159             sub { Net::Packet::PPP->new(raw => shift()) },
160             NP_LAYER_LLC() =>
161             sub { Net::Packet::LLC->new(raw => shift()) },
162             NP_LAYER_PPPLCP() =>
163             sub { Net::Packet::PPPLCP->new(raw => shift()) },
164             NP_LAYER_CDP() =>
165             sub { Net::Packet::CDP->new(raw => shift()) },
166             NP_LAYER_STP() =>
167             sub { Net::Packet::STP->new(raw => shift()) },
168             NP_LAYER_OSPF() =>
169             sub { Net::Packet::OSPF->new(raw => shift()) },
170             NP_LAYER_IGMPv4() =>
171             sub { Net::Packet::IGMPv4->new(raw => shift()) },
172             NP_LAYER_7() =>
173             sub { Net::Packet::Layer7->new(raw => shift()) },
174             };
175              
176             my $mapNum = {
177             'L?' => 0,
178             'L2' => 2,
179             'L3' => 3,
180             'L4' => 4,
181             'L7' => 7,
182             };
183              
184             sub unpack {
185             my $self = shift;
186              
187             my $encapsulate = $self->[$__encapsulate];
188              
189             if ($encapsulate eq NP_LAYER_UNKNOWN) {
190             print("Unable to unpack Frame from this layer type, ".
191             "not yet implemented (maybe should be in Dump)\n");
192             return undef;
193             }
194              
195             my $doMemoryOptimizations = $self->[$__env]->doMemoryOptimizations;
196              
197             my @frames;
198             my $prev;
199             my $n = 0;
200             my $raw = $self->[$__raw];
201             my $rawLength = length($raw);
202             my $oRaw = $raw;
203             # No more than a thousand nested layers, maybe should be an Env param
204             for (1..1000) {
205             last unless $raw;
206              
207             my $l = $whichLink->{$encapsulate}($raw);
208              
209             $encapsulate = $l->encapsulate;
210             $raw = $l->payload;
211              
212             if ($doMemoryOptimizations) {
213             $l->raw(undef);
214             $l->payload(undef);
215             $l = $l->cgClone;
216             }
217              
218             # Frame creation handling
219             if ($prev && $mapNum->{$l->layer} <= $mapNum->{$prev->layer}) {
220             $n++;
221             }
222             $prev = $l;
223              
224             unless ($frames[$n]) {
225             $frames[$n] = Net::Packet::Frame->new;
226             $frames[$n]->[$__raw] = $oRaw;
227              
228             # We strip the payload for last layer of previously built frame,
229             # because it is now analyzed within the new frame
230             my $m = $n - 1;
231             if ($m >= 0) {
232             if ($frames[$m]->[$__l7]) { $frames[$m]->[$__l7]->payload(undef)}
233             elsif ($frames[$m]->[$__l4]) { $frames[$m]->[$__l4]->payload(undef)}
234             elsif ($frames[$m]->[$__l3]) { $frames[$m]->[$__l3]->payload(undef)}
235             elsif ($frames[$m]->[$__l2]) { $frames[$m]->[$__l2]->payload(undef)}
236             }
237             }
238             if ($l->isLayer2) { $frames[$n]->[$__l2] = $l }
239             elsif ($l->isLayer3) { $frames[$n]->[$__l3] = $l }
240             elsif ($l->isLayer4) { $frames[$n]->[$__l4] = $l }
241             elsif ($l->isLayer7) { $frames[$n]->[$__l7] = $l }
242             # / Frame creation handling
243              
244             if ($encapsulate eq NP_LAYER_UNKNOWN) {
245             print("Unable to unpack next Layer, not yet implemented in Layer: ".
246             "$n:@{[$l->is]}\n");
247             last;
248             }
249              
250             last if $encapsulate eq NP_LAYER_NONE;
251              
252             $oRaw = $raw;
253             }
254              
255             $frames[-1]->_getPadding($rawLength);
256              
257             $self->[$__env]->doFrameReturnList ? \@frames : $frames[0];
258             }
259              
260             sub pack {
261             my $self = shift;
262              
263             my $env = $self->[$__env];
264             my $l2 = $self->[$__l2];
265             my $l3 = $self->[$__l3];
266             my $l4 = $self->[$__l4];
267             my $l7 = $self->[$__l7];
268              
269             my $noChecksums = $env->noFrameComputeChecksums;
270             my $noLengths = $env->noFrameComputeLengths;
271             if (! $noChecksums && ! $noLengths) {
272             if ($l2) {
273             $l2->computeLengths($env, $l2, $l3, $l4, $l7) or return undef;
274             $l2->computeChecksums($env, $l2, $l3, $l4, $l7) or return undef;
275             $l2->pack or return undef;
276             }
277             if ($l3) {
278             $l3->computeLengths($env, $l2, $l3, $l4, $l7) or return undef;
279             $l3->computeChecksums($env, $l2, $l3, $l4, $l7) or return undef;
280             $l3->pack or return undef;
281             }
282             if ($l4) {
283             $l4->computeLengths($env, $l2, $l3, $l4, $l7) or return undef;
284             $l4->computeChecksums($env, $l2, $l3, $l4, $l7) or return undef;
285             $l4->pack or return undef;
286             }
287             if ($l7) {
288             $l7->computeLengths($env, $l2, $l3, $l4, $l7) or return undef;
289             $l7->computeChecksums($env, $l2, $l3, $l4, $l7) or return undef;
290             $l7->pack or return undef;
291             }
292             }
293             elsif (! $noChecksums && $noLengths) {
294             if ($l2) {
295             $l2->computeChecksums($env, $l2, $l3, $l4, $l7) or return undef;
296             $l2->pack or return undef;
297             }
298             if ($l3) {
299             $l3->computeChecksums($env, $l2, $l3, $l4, $l7) or return undef;
300             $l3->pack or return undef;
301             }
302             if ($l4) {
303             $l4->computeChecksums($env, $l2, $l3, $l4, $l7) or return undef;
304             $l4->pack or return undef;
305             }
306             if ($l7) {
307             $l7->computeChecksums($env, $l2, $l3, $l4, $l7) or return undef;
308             $l7->pack or return undef;
309             }
310             }
311             else {
312             if ($l2) { $l2->pack or return undef }
313             if ($l3) { $l3->pack or return undef }
314             if ($l4) { $l4->pack or return undef }
315             if ($l7) { $l7->pack or return undef }
316             }
317              
318              
319             my $raw;
320             $raw .= $self->[$__l2]->raw if $self->[$__l2];
321             $raw .= $self->[$__l3]->raw if $self->[$__l3];
322             $raw .= $self->[$__l4]->raw if $self->[$__l4];
323             $raw .= $self->[$__l7]->raw if $self->[$__l7];
324             $raw .= $self->[$__padding] if $self->[$__padding];
325              
326             if ($raw) {
327             $self->[$__raw] = $raw;
328             $self->_padFrame unless $env->noFramePadding;
329             }
330              
331             if ($env->doMemoryOptimizations) {
332             if ($self->[$__l2]) {
333             $self->[$__l2]->raw(undef);
334             $self->[$__l2]->payload(undef);
335             $self->[$__l2] = $self->[$__l2]->cgClone;
336             }
337             if ($self->[$__l3]) {
338             $self->[$__l3]->raw(undef);
339             $self->[$__l3]->payload(undef);
340             $self->[$__l3] = $self->[$__l3]->cgClone;
341             }
342             if ($self->[$__l4]) {
343             $self->[$__l4]->raw(undef);
344             $self->[$__l4]->payload(undef);
345             $self->[$__l4] = $self->[$__l4]->cgClone;
346             }
347             if ($self->[$__l7]) {
348             $self->[$__l7]->raw(undef);
349             $self->[$__l7]->payload(undef);
350             $self->[$__l7] = $self->[$__l7]->cgClone;
351             }
352             }
353              
354             $self;
355             }
356              
357             sub _padFrame {
358             my $self = shift;
359              
360             # Pad this frame, if sent from layer 2
361             if ($self->[$__l2]) {
362             my $rawLength = length($self->[$__raw]);
363             if ($rawLength < 60) {
364             my $padding = ('G' x (60 - $rawLength));
365             $self->[$__raw] = $self->[$__raw].$padding;
366             }
367             }
368             }
369              
370             sub _getPadding {
371             my $self = shift;
372             my ($rawLength) = @_;
373              
374             my $thisLength = length($self->[$__raw]);
375              
376             # There is a chance this is a memory bug to align with 60 bytes
377             # We check it to see if it is true Layer7, or just a padding
378             if ($self->[$__l7] && $thisLength == 60
379             && $self->[$__l3] && $self->[$__l4]) {
380             my $pLen = $self->[$__l3]->getPayloadLength;
381             my $nLen = $self->[$__l4]->getLength;
382             if ($pLen == $nLen) {
383             $self->[$__padding] = $self->[$__l7]->data;
384             $self->[$__l7] = undef;
385             }
386             return 1;
387             }
388              
389             # No padding
390             return 1 if $rawLength > 60;
391              
392             my $len = $self->getLengthFromL2;
393             my $padding = substr($self->[$__raw], $len, $rawLength - $len);
394             $self->[$__padding] = $padding;
395             }
396              
397             sub send {
398             my $self = shift;
399              
400             my $env = $self->[$__env];
401              
402             if ($env->dump && ! $env->dump->isRunning) {
403             $env->dump->start;
404             $self->cgDebugPrint(1, "Dump object started");
405             }
406              
407             if ($env->debug >= 3) {
408             if ($self->isEth) {
409             $self->cgDebugPrint(3,
410             "send: l2: type:". sprintf("0x%x", $self->l2->type). ", ".
411             "@{[$self->l2->src]} => @{[$self->l2->dst]}"
412             );
413             }
414              
415             if ($self->isIp) {
416             $self->cgDebugPrint(3,
417             "send: l3: protocol:@{[$self->l3->protocol]}, ".
418             "size:@{[$self->getLength]}, ".
419             "@{[$self->l3->src]} => @{[$self->l3->dst]}"
420             );
421             }
422             elsif ($self->isArp) {
423             $self->cgDebugPrint(3,
424             "send: l3: @{[$self->l3->src]} => @{[$self->l3->dst]}"
425             );
426             }
427              
428             if ($self->isTcp || $self->isUdp) {
429             $self->cgDebugPrint(3,
430             "send: l4: @{[$self->l4->is]}, ".
431             "@{[$self->l4->src]} => @{[$self->l4->dst]}"
432             );
433             }
434             }
435              
436             $self->[$__timestamp] = _gettimeofday();
437             if ($env->desc) {
438             $env->desc->send($self->[$__raw]);
439             }
440             else {
441             carp("@{[(caller(0))[3]]}: no Desc open, can't send Frame\n");
442             return undef;
443             }
444             1;
445             }
446              
447             sub reSend { my $self = shift; $self->send unless $self->[$__reply] }
448              
449             sub getFilter {
450             my $self = shift;
451              
452             my $filter;
453              
454             # L4 filtering
455             if ($self->[$__l4]) {
456             if ($self->isTcp) {
457             $filter .= "(tcp and".
458             " src port @{[$self->[$__l4]->dst]}".
459             " and dst port @{[$self->[$__l4]->src]})";
460             }
461             elsif ($self->isUdp) {
462             $filter .= "(udp and".
463             " src port @{[$self->[$__l4]->dst]}".
464             " and dst port @{[$self->[$__l4]->src]})";
465             }
466             elsif ($self->isIcmpv4) {
467             $filter .= "(icmp)";
468             }
469             $filter .= " or icmp";
470             }
471              
472             # L3 filtering
473             if ($self->[$__l3]) {
474             $filter .= " and " if $filter;
475              
476             if ($self->isIpv4) {
477             $filter .= "(src host @{[$self->[$__l3]->dst]}".
478             " and dst host @{[$self->[$__l3]->src]}) ".
479             " or ".
480             "(icmp and dst host @{[$self->[$__l3]->src]})";
481             }
482             elsif ($self->isIpv6) {
483             $filter .= "(ip6 and src host @{[$self->[$__l3]->dst]}".
484             " and dst host @{[$self->[$__l3]->src]})";
485             }
486             elsif ($self->isArp) {
487             $filter .= "(arp and src host @{[$self->[$__l3]->dstIp]}".
488             " and dst host @{[$self->[$__l3]->srcIp]})";
489             }
490             }
491            
492             $filter;
493             }
494              
495             sub recv {
496             my $self = shift;
497              
498             $self->[$__env]->dump->nextAll if $self->[$__env]->dump->isRunning;
499              
500             # We already have the reply
501             return undef if $self->[$__reply];
502              
503             croak("@{[(caller(0))[3]]}: \$self->env->dump variable not set\n")
504             unless $self->[$__env]->dump;
505              
506             if ($self->[$__l4] && $self->[$__l4]->can('recv')) {
507             $self->[$__reply] = $self->[$__l4]->recv($self);
508             }
509             elsif ($self->[$__l3] && $self->[$__l3]->can('recv')) {
510             $self->[$__reply] = $self->[$__l3]->recv($self);
511             }
512             else {
513             carp("@{[(caller(0))[3]]}: not implemented for this Layer\n");
514             return undef;
515             }
516              
517             $self->[$__reply]
518             ? do { $self->cgDebugPrint(1, "Reply received"); return $self->[$__reply]}
519             : return undef;
520             }
521              
522             sub print {
523             my $self = shift;
524             my $str = '';
525             $str .= $self->[$__l2]->print."\n" if $self->[$__l2];
526             $str .= $self->[$__l3]->print."\n" if $self->[$__l3];
527             $str .= $self->[$__l4]->print."\n" if $self->[$__l4];
528             $str .= $self->[$__l7]->print."\n" if $self->[$__l7];
529              
530             $str =~ s/\n$//s;
531              
532             # Print remaining to be decoded, if any
533             if ($self->[$__l7]) {
534             $str .= "\n".'L7: payload:'.CORE::unpack('H*', $self->[$__l7]->payload)
535             if $self->[$__l7]->payload;
536             }
537             elsif ($self->[$__l4]) {
538             $str .= "\n".'L4: payload:'.CORE::unpack('H*', $self->[$__l4]->payload)
539             if $self->[$__l4]->payload;
540             }
541             elsif ($self->[$__l3]) {
542             $str .= "\n".'L3: payload:'.CORE::unpack('H*', $self->[$__l3]->payload)
543             if $self->[$__l3]->payload;
544             }
545             elsif ($self->[$__l2]) {
546             $str .= "\n".'L2: payload:'.CORE::unpack('H*', $self->[$__l2]->payload)
547             if $self->[$__l2]->payload;
548             }
549              
550             # Print the padding, if any
551             if ($self->[$__padding]) {
552             $str .= "\n".'Padding: '.CORE::unpack('H*', $self->[$__padding]);
553             }
554              
555             $str;
556             }
557              
558             sub dump {
559             my $self = shift;
560             my $str = '';
561             $str .= $self->[$__l2]->dump."\n" if $self->[$__l2];
562             $str .= $self->[$__l3]->dump."\n" if $self->[$__l3];
563             $str .= $self->[$__l4]->dump."\n" if $self->[$__l4];
564             $str .= $self->[$__l7]->dump."\n" if $self->[$__l7];
565             if ($self->[$__padding]) {
566             $str .= 'Padding: '.CORE::unpack('H*', $self->[$__padding])."\n";
567             }
568             $str;
569             }
570              
571             #
572             # Helpers
573             #
574              
575             sub _isL2 { my $self = shift; $self->[$__l2] && $self->[$__l2]->is eq shift() }
576             sub _isL3 { my $self = shift; $self->[$__l3] && $self->[$__l3]->is eq shift() }
577             sub _isL4 { my $self = shift; $self->[$__l4] && $self->[$__l4]->is eq shift() }
578             sub _isL7 { my $self = shift; $self->[$__l7] && $self->[$__l7]->is eq shift() }
579             sub isEth { shift->_isL2(NP_LAYER_ETH) }
580             sub isRaw { shift->_isL2(NP_LAYER_RAW) }
581             sub isNull { shift->_isL2(NP_LAYER_NULL) }
582             sub isSll { shift->_isL2(NP_LAYER_SLL) }
583             sub isPpp { shift->_isL2(NP_LAYER_PPP) }
584             sub isArp { shift->_isL3(NP_LAYER_ARP) }
585             sub isIpv4 { shift->_isL3(NP_LAYER_IPv4) }
586             sub isIpv6 { shift->_isL3(NP_LAYER_IPv6) }
587             sub isVlan { shift->_isL3(NP_LAYER_VLAN) }
588             sub isPppoe { shift->_isL3(NP_LAYER_PPPoE) }
589             sub isLlc { shift->_isL3(NP_LAYER_LLC) }
590             sub isTcp { shift->_isL4(NP_LAYER_TCP) }
591             sub isUdp { shift->_isL4(NP_LAYER_UDP) }
592             sub isIcmpv4 { shift->_isL4(NP_LAYER_ICMPv4) }
593             sub isPpplcp { shift->_isL4(NP_LAYER_PPPLCP) }
594             sub isCdp { shift->_isL4(NP_LAYER_CDP) }
595             sub isStp { shift->_isL4(NP_LAYER_STP) }
596             sub isOspf { shift->_isL4(NP_LAYER_OSPF) }
597             sub isIgmpv4 { shift->_isL4(NP_LAYER_IGMPv4) }
598             sub is7 { shift->_isL7(NP_LAYER_7) }
599             sub isIp { my $self = shift; $self->isIpv4 || $self->isIpv6 }
600             sub isIcmp { my $self = shift; $self->isIcmpv4 } # XXX: || v6
601              
602             1;
603              
604             __END__