File Coverage

blib/lib/Net/Frame/Layer/ICMPv6.pm
Criterion Covered Total %
statement 143 221 64.7
branch 2 60 3.3
condition 0 35 0.0
subroutine 47 54 87.0
pod 10 10 100.0
total 202 380 53.1


line stmt bran cond sub pod time code
1             #
2             # $Id: ICMPv6.pm 45 2014-04-09 06:32:08Z gomor $
3             #
4             package Net::Frame::Layer::ICMPv6;
5 2     2   23537 use strict; use warnings;
  2     2   5  
  2         84  
  2         11  
  2         3  
  2         112  
6              
7             our $VERSION = '1.09';
8              
9 2     2   5023 use Net::Frame::Layer qw(:consts :subs);
  2         266422  
  2         647  
10 2     2   26 use Exporter;
  2         3  
  2         303  
11             our @ISA = qw(Net::Frame::Layer Exporter);
12              
13             our %EXPORT_TAGS = (
14             consts => [qw(
15             NF_ICMPv6_CODE_ZERO
16             NF_ICMPv6_TYPE_DESTUNREACH
17             NF_ICMPv6_CODE_NOROUTE
18             NF_ICMPv6_CODE_ADMINPROHIBITED
19             NF_ICMPv6_CODE_NOTASSIGNED
20             NF_ICMPv6_CODE_ADDRESSUNREACH
21             NF_ICMPv6_CODE_PORTUNREACH
22             NF_ICMPv6_CODE_FAILPOLICY
23             NF_ICMPv6_CODE_REJECTROUTE
24             NF_ICMPv6_TYPE_TOOBIG
25             NF_ICMPv6_TYPE_TIMEEXCEED
26             NF_ICMPv6_CODE_HOPLIMITEXCEED
27             NF_ICMPv6_CODE_FRAGREASSEMBLYEXCEEDED
28             NF_ICMPv6_TYPE_PARAMETERPROBLEM
29             NF_ICMPv6_CODE_ERRONEOUSHERDERFIELD
30             NF_ICMPv6_CODE_UNKNOWNNEXTHEADER
31             NF_ICMPv6_CODE_UNKNOWNOPTION
32             NF_ICMPv6_TYPE_ECHO_REQUEST
33             NF_ICMPv6_TYPE_ECHO_REPLY
34             NF_ICMPv6_TYPE_ROUTERSOLICITATION
35             NF_ICMPv6_TYPE_ROUTERADVERTISEMENT
36             NF_ICMPv6_TYPE_NEIGHBORSOLICITATION
37             NF_ICMPv6_TYPE_NEIGHBORADVERTISEMENT
38             NF_ICMPv6_OPTION_SOURCELINKLAYERADDRESS
39             NF_ICMPv6_OPTION_TARGETLINKLAYERADDRESS
40             NF_ICMPv6_OPTION_PREFIXINFORMATION
41             NF_ICMPv6_OPTION_REDIRECTEDHEADER
42             NF_ICMPv6_OPTION_MTU
43             NF_ICMPv6_FLAG_ROUTER
44             NF_ICMPv6_FLAG_SOLICITED
45             NF_ICMPv6_FLAG_OVERRIDE
46             NF_ICMPv6_FLAG_MANAGEDADDRESSCONFIGURATION
47             NF_ICMPv6_FLAG_OTHERCONFIGURATION
48             )],
49             );
50             our @EXPORT_OK = (
51             @{$EXPORT_TAGS{consts}},
52             );
53              
54 2     2   13 use constant NF_ICMPv6_CODE_ZERO => 0;
  2         4  
  2         138  
55 2     2   11 use constant NF_ICMPv6_TYPE_DESTUNREACH => 1;
  2         3  
  2         95  
56 2     2   11 use constant NF_ICMPv6_CODE_NOROUTE => 0;
  2         5  
  2         87  
57 2     2   10 use constant NF_ICMPv6_CODE_ADMINPROHIBITED => 1;
  2         4  
  2         92  
58 2     2   10 use constant NF_ICMPv6_CODE_NOTASSIGNED => 2;
  2         4  
  2         176  
59 2     2   21 use constant NF_ICMPv6_CODE_ADDRESSUNREACH => 3;
  2         6  
  2         102  
60 2     2   12 use constant NF_ICMPv6_CODE_PORTUNREACH => 4;
  2         4  
  2         103  
61 2     2   11 use constant NF_ICMPv6_CODE_FAILPOLICY => 5;
  2         3  
  2         94  
62 2     2   23 use constant NF_ICMPv6_CODE_REJECTROUTE => 6;
  2         4  
  2         120  
63 2     2   16 use constant NF_ICMPv6_TYPE_TOOBIG => 2;
  2         4  
  2         87  
64 2     2   9 use constant NF_ICMPv6_TYPE_TIMEEXCEED => 3;
  2         4  
  2         98  
65 2     2   11 use constant NF_ICMPv6_CODE_HOPLIMITEXCEED => 0;
  2         4  
  2         116  
66 2     2   11 use constant NF_ICMPv6_CODE_FRAGREASSEMBLYEXCEEDED => 1;
  2         3  
  2         87  
67 2     2   10 use constant NF_ICMPv6_TYPE_PARAMETERPROBLEM => 4;
  2         3  
  2         216  
68 2     2   12 use constant NF_ICMPv6_CODE_ERRONEOUSHERDERFIELD => 0;
  2         4  
  2         122  
69 2     2   10 use constant NF_ICMPv6_CODE_UNKNOWNNEXTHEADER => 1;
  2         4  
  2         105  
70 2     2   10 use constant NF_ICMPv6_CODE_UNKNOWNOPTION => 2;
  2         4  
  2         98  
71 2     2   11 use constant NF_ICMPv6_TYPE_ECHO_REQUEST => 128;
  2         5  
  2         184  
72 2     2   13 use constant NF_ICMPv6_TYPE_ECHO_REPLY => 129;
  2         4  
  2         94  
73 2     2   28 use constant NF_ICMPv6_TYPE_ROUTERSOLICITATION => 133;
  2         3  
  2         94  
74 2     2   12 use constant NF_ICMPv6_TYPE_ROUTERADVERTISEMENT => 134;
  2         3  
  2         92  
75 2     2   9 use constant NF_ICMPv6_TYPE_NEIGHBORSOLICITATION => 135;
  2         3  
  2         118  
76 2     2   19 use constant NF_ICMPv6_TYPE_NEIGHBORADVERTISEMENT => 136;
  2         5  
  2         99  
77              
78 2     2   10 use constant NF_ICMPv6_OPTION_SOURCELINKLAYERADDRESS => 0x01;
  2         4  
  2         90  
79 2     2   11 use constant NF_ICMPv6_OPTION_TARGETLINKLAYERADDRESS => 0x02;
  2         4  
  2         105  
80 2     2   11 use constant NF_ICMPv6_OPTION_PREFIXINFORMATION => 0x03;
  2         10  
  2         91  
81 2     2   11 use constant NF_ICMPv6_OPTION_REDIRECTEDHEADER => 0x04;
  2         20  
  2         108  
82 2     2   11 use constant NF_ICMPv6_OPTION_MTU => 0x05;
  2         3  
  2         89  
83              
84 2     2   10 use constant NF_ICMPv6_FLAG_ROUTER => 0x04;
  2         4  
  2         1700  
85 2     2   19 use constant NF_ICMPv6_FLAG_SOLICITED => 0x02;
  2         4  
  2         98  
86 2     2   10 use constant NF_ICMPv6_FLAG_OVERRIDE => 0x01;
  2         20  
  2         99  
87              
88 2     2   10 use constant NF_ICMPv6_FLAG_MANAGEDADDRESSCONFIGURATION => 1 << 5;
  2         4  
  2         91  
89 2     2   10 use constant NF_ICMPv6_FLAG_OTHERCONFIGURATION => 1 << 4;
  2         4  
  2         122  
90 2     2   11 use constant NF_ICMPv6_FLAG_MOBILEIPv6HOMEAGENT => 1 << 3;
  2         3  
  2         94  
91 2     2   10 use constant NF_ICMPv6_FLAG_ROUTERSELECTIONPREFHIGH => 1 << 1; # 01b
  2         12  
  2         86  
92 2     2   11 use constant NF_ICMPv6_FLAG_ROUTERSELECTIONPREFMEDIUM => 0; # 00b
  2         4  
  2         248  
93 2     2   10 use constant NF_ICMPv6_FLAG_ROUTERSELECTIONPREFLOW => 3 << 1; # 11b
  2         4  
  2         128  
94 2     2   10 use constant NF_ICMPv6_FLAG_ROUTERSELECTIONPREFRESERVED => 2 << 1; # 10b
  2         5  
  2         101  
95 2     2   11 use constant NF_ICMPv6_FLAG_NEIGHBORDISCOVERYPROXY => 1;
  2         4  
  2         185  
96              
97             our @AS = qw(
98             type
99             code
100             checksum
101             );
102             __PACKAGE__->cgBuildIndices;
103             __PACKAGE__->cgBuildAccessorsScalar(\@AS);
104              
105 2     2   2665 use Bit::Vector;
  2         11412  
  2         4974  
106              
107             sub new {
108             shift->SUPER::new(
109 1     1 1 37 type => NF_ICMPv6_TYPE_ECHO_REQUEST,
110             code => NF_ICMPv6_CODE_ZERO,
111             checksum => 0,
112             @_,
113             );
114             }
115              
116             # XXX: may be better, by keying on type also
117 0     0 1 0 sub getKey { shift->layer }
118 0     0 1 0 sub getKeyReverse { shift->layer }
119              
120             sub match {
121 0     0 1 0 my $self = shift;
122 0         0 my ($with) = @_;
123 0         0 my $sType = $self->type;
124 0         0 my $wType = $with->type;
125 0 0 0     0 if ($sType eq NF_ICMPv6_TYPE_ECHO_REQUEST
    0 0        
    0 0        
126             && $wType eq NF_ICMPv6_TYPE_ECHO_REPLY) {
127 0         0 return 1;
128             }
129             elsif ($sType eq NF_ICMPv6_TYPE_NEIGHBORSOLICITATION
130             && $wType eq NF_ICMPv6_TYPE_NEIGHBORADVERTISEMENT) {
131 0         0 return 1;
132             }
133             elsif ($sType eq NF_ICMPv6_TYPE_ROUTERSOLICITATION
134             && $wType eq NF_ICMPv6_TYPE_ROUTERADVERTISEMENT) {
135 0         0 return 1;
136             }
137 0         0 return 0;
138             }
139              
140 0     0 1 0 sub getLength { 4 }
141              
142             sub pack {
143 1     1 1 287 my $self = shift;
144              
145 1 50       7 my $raw = $self->SUPER::pack('CCn',
146             $self->type, $self->code, $self->checksum,
147             ) or return;
148              
149 1         76 return $self->raw($raw);
150             }
151              
152             sub unpack {
153 1     1 1 15 my $self = shift;
154              
155 1 50       20 my ($type, $code, $checksum, $payload) =
156             $self->SUPER::unpack('CCn a*', $self->raw)
157             or return;
158              
159 1         1158 $self->type($type);
160 1         21 $self->code($code);
161 1         13 $self->checksum($checksum);
162 1         18 $self->payload($payload);
163              
164 1         25 return $self;
165             }
166              
167             sub computeChecksums {
168 0     0 1   my $self = shift;
169 0           my ($layers) = @_;
170              
171 0           my $icmpType;
172             my $ip;
173 0           my $rh0;
174 0           my $hbh; # Hop-by-hop Ext Hdr
175 0           my $dst; # Destination Ext Hdr
176 0           my $mob; # Mobility Ext Hdr
177 0           my $lastNextHeader;
178 0           my $fragmentFlag = 0;
179 0           for my $l (@$layers) {
180 0 0 0       if (! $icmpType && $l->layer =~ /ICMPv6::/) { $icmpType = $l; }
  0            
181 0 0 0       if (! $ip && $l->layer eq 'IPv6') { $ip = $l; }
  0            
182 0 0 0       if (! $rh0 && $l->layer eq 'IPv6::Routing') { $rh0 = $l; }
  0            
183 0 0 0       if (! $hbh && $l->layer eq 'IPv6::HopByHop') { $hbh = $l; }
  0            
184 0 0 0       if (! $dst && $l->layer eq 'IPv6::Destination') { $dst = $l; }
  0            
185 0 0 0       if (! $mob && $l->layer eq 'IPv6::Mobility') { $mob = $l; }
  0            
186              
187 0 0         if ($l->can('nextHeader')) { $lastNextHeader = $l->nextHeader; }
  0            
188              
189 0 0         if ($l->layer eq 'IPv6::Fragment') { $fragmentFlag = 1; }
  0            
190             }
191              
192 0           my $lastIpDst = $ip->dst;
193 0           my $ipPayloadLength = $ip->payloadLength;
194             # If RH0, need to set $ip->dst to last $rh0->addresses
195             # unless segmentsLeft == 0 (RFC 2460 sec 8.1)
196 0 0 0       if ($rh0 && $rh0->segmentsLeft != 0) {
197 0           for ($rh0->addresses) {
198 0           $lastIpDst = $_;
199             }
200             # Pseudo header length is upper layer minus any EH (RFC 2460 sec 8.1)
201 0           $ipPayloadLength -= $rh0->getLength;
202             }
203             # Pseudo header length is upper layer minus any EH (RFC 2460 sec 8.1)
204 0 0         if ($fragmentFlag) {
205 0           $ipPayloadLength -= 8; # 8 = length of fragment EH
206             }
207 0 0         if ($hbh) {
208 0           $ipPayloadLength -= $hbh->getLength;
209             }
210 0 0         if ($dst) {
211 0           $ipPayloadLength -= $dst->getLength;
212             }
213 0 0         if ($mob) {
214 0           $ipPayloadLength -= $mob->getLength;
215             }
216              
217             # Build pseudo-header and pack ICMPv6 packet
218 0           my $zero = Bit::Vector->new_Dec(24, 0);
219 0           my $nextHeader = Bit::Vector->new_Dec( 8, $lastNextHeader);
220 0           my $v32 = $zero->Concat_List($nextHeader);
221              
222 0 0         my $packed = $self->SUPER::pack('a*a*NNCCna*',
223             inet6Aton($ip->src), inet6Aton($lastIpDst), $ipPayloadLength,
224             $v32->to_Dec, $self->type, $self->code, 0, $icmpType->pack,
225             ) or return;
226              
227 0   0       my $payload = $layers->[-1]->payload || '';
228 0           $self->checksum(inetChecksum($packed.$payload));
229              
230 0           return 1;
231             }
232              
233             sub encapsulate {
234 0     0 1   my $self = shift;
235              
236 0 0         return $self->nextLayer if $self->nextLayer;
237              
238 0 0         if ($self->payload) {
239 0           my $type = $self->type;
240             # if ($type eq NF_ICMPv6_TYPE_REDIRECT) {
241             # return 'IPv6';
242             # }
243 0 0 0       if ($type eq NF_ICMPv6_TYPE_ECHO_REQUEST
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
244             || $type eq NF_ICMPv6_TYPE_ECHO_REPLY) {
245 0           return 'ICMPv6::Echo';
246             }
247             elsif ($type eq NF_ICMPv6_TYPE_NEIGHBORSOLICITATION) {
248 0           return 'ICMPv6::NeighborSolicitation';
249             }
250             elsif ($type eq NF_ICMPv6_TYPE_NEIGHBORADVERTISEMENT) {
251 0           return 'ICMPv6::NeighborAdvertisement';
252             }
253             elsif ($type eq NF_ICMPv6_TYPE_ROUTERSOLICITATION) {
254 0           return 'ICMPv6::RouterSolicitation';
255             }
256             elsif ($type eq NF_ICMPv6_TYPE_ROUTERADVERTISEMENT) {
257 0           return 'ICMPv6::RouterAdvertisement';
258             }
259             elsif ($type eq NF_ICMPv6_TYPE_DESTUNREACH) {
260 0           return 'ICMPv6::DestUnreach';
261             }
262             elsif ($type eq NF_ICMPv6_TYPE_TIMEEXCEED) {
263 0           return 'ICMPv6::TimeExceed';
264             }
265             elsif ($type eq NF_ICMPv6_TYPE_TOOBIG) {
266 0           return 'ICMPv6::TooBig';
267             }
268             elsif ($type eq NF_ICMPv6_TYPE_PARAMETERPROBLEM) {
269 0           return 'ICMPv6::ParameterProblem';
270             }
271             }
272              
273 0           return NF_LAYER_NONE;
274             }
275              
276             sub print {
277 0     0 1   my $self = shift;
278              
279 0           my $l = $self->layer;
280 0           my $buf = sprintf "$l: type:%d code:%d checksum:0x%04x",
281             $self->type, $self->code, $self->checksum;
282              
283 0           return $buf;
284             }
285              
286             1;
287              
288             __END__