File Coverage

blib/lib/NetPacket/IPv6.pm
Criterion Covered Total %
statement 110 123 89.4
branch 13 24 54.1
condition 2 3 66.6
subroutine 22 23 95.6
pod 5 5 100.0
total 152 178 85.3


line stmt bran cond sub pod time code
1             package NetPacket::IPv6;
2             our $AUTHORITY = 'cpan:YANICK';
3             # ABSTRACT: Assemble and disassemble IPv6 (Internet Protocol version 6) packets.
4             $NetPacket::IPv6::VERSION = '1.7.2';
5 2     2   69612 use strict;
  2         13  
  2         59  
6 2     2   10 use warnings;
  2         4  
  2         54  
7              
8 2     2   446 use parent 'NetPacket';
  2         322  
  2         10  
9 2     2   1019 use NetPacket::IP qw(:protos :tos :misc);
  2         5  
  2         758  
10 2     2   1200 use Socket 1.87 qw(AF_INET6 inet_pton inet_ntop);
  2         7700  
  2         539  
11              
12             our @EXPORT_OK = (qw(ipv6_strip ipv6_extheader),
13             @{$NetPacket::IP::EXPORT_TAGS{protos}},
14             qw(IP_VERSION_IPv6),
15             @{$NetPacket::IP::EXPORT_TAGS{tos}},
16             @{$NetPacket::IP::EXPORT_TAGS{misc}},
17             qw(IPv6_EXTHEADER_HOPBYHOP IPv6_EXTHEADER_ROUTING IPv6_EXTHEADER_FRAGMENT
18             IPv6_EXTHEADER_ESP IPv6_EXTHEADER_AUTH IPv6_EXTHEADER_NONEXT IPv6_EXTHEADER_DESTOPT
19             IPv6_EXTHEADER_MOBILITY IPv6_EXTHEADER_HOSTIDENT IPv6_EXTHEADER_SHIM6
20             IPv6_EXTHEADER_TESTING1 IPv6_EXTHEADER_TESTING2),
21             );
22              
23             our %EXPORT_TAGS = (
24             ALL => [@EXPORT_OK],
25             protos => [@{$NetPacket::IP::EXPORT_TAGS{protos}}],
26             versions => [qw(IP_VERSION_IPv6)],
27             strip => [qw(ipv6_strip)],
28             tos => [@{$NetPacket::IP::EXPORT_TAGS{tos}}],
29             misc => [@{$NetPacket::IP::EXPORT_TAGS{misc}}],
30             extheaders => [qw(IPv6_EXTHEADER_HOPBYHOP IPv6_EXTHEADER_ROUTING IPv6_EXTHEADER_FRAGMENT
31             IPv6_EXTHEADER_ESP IPv6_EXTHEADER_AUTH IPv6_EXTHEADER_NONEXT IPv6_EXTHEADER_DESTOPT
32             IPv6_EXTHEADER_MOBILITY IPv6_EXTHEADER_HOSTIDENT IPv6_EXTHEADER_SHIM6
33             IPv6_EXTHEADER_TESTING1 IPv6_EXTHEADER_TESTING2)],
34             );
35              
36             #
37             # Partial list of IP version numbers from RFC 8200
38             #
39              
40 2     2   16 use constant IP_VERSION_IPv6 => 6; # IP version 6
  2         4  
  2         110  
41              
42             #
43             # List of IPv6 extension header types from RFC 7045
44             #
45              
46 2     2   11 use constant IPv6_EXTHEADER_HOPBYHOP => 0;
  2         4  
  2         84  
47 2     2   11 use constant IPv6_EXTHEADER_ROUTING => 43;
  2         3  
  2         80  
48 2     2   11 use constant IPv6_EXTHEADER_FRAGMENT => 44;
  2         2  
  2         79  
49 2     2   10 use constant IPv6_EXTHEADER_ESP => 50;
  2         5  
  2         76  
50 2     2   10 use constant IPv6_EXTHEADER_AUTH => 51;
  2         4  
  2         74  
51 2     2   10 use constant IPv6_EXTHEADER_NONEXT => 59;
  2         3  
  2         75  
52 2     2   10 use constant IPv6_EXTHEADER_DESTOPT => 60;
  2         3  
  2         78  
53 2     2   10 use constant IPv6_EXTHEADER_MOBILITY => 135;
  2         4  
  2         74  
54 2     2   11 use constant IPv6_EXTHEADER_HOSTIDENT => 139;
  2         3  
  2         73  
55 2     2   10 use constant IPv6_EXTHEADER_SHIM6 => 140;
  2         4  
  2         71  
56 2     2   11 use constant IPv6_EXTHEADER_TESTING1 => 253;
  2         7  
  2         72  
57 2     2   11 use constant IPv6_EXTHEADER_TESTING2 => 254;
  2         3  
  2         2006  
58              
59             # Check if the next header is an IPv6 extension header
60              
61             my %is_extheader = map { ($_ => 1) }
62             IPv6_EXTHEADER_HOPBYHOP, IPv6_EXTHEADER_ROUTING, IPv6_EXTHEADER_FRAGMENT,
63             IPv6_EXTHEADER_ESP, IPv6_EXTHEADER_AUTH, IPv6_EXTHEADER_DESTOPT,
64             IPv6_EXTHEADER_MOBILITY, IPv6_EXTHEADER_HOSTIDENT, IPv6_EXTHEADER_SHIM6,
65             IPv6_EXTHEADER_TESTING1, IPv6_EXTHEADER_TESTING2;
66              
67             sub ipv6_extheader {
68 25     25 1 64 my($type) = @_;
69 25         90 return !!exists $is_extheader{$type};
70             }
71              
72             #
73             # Decode the packet
74             #
75              
76             sub decode {
77 19     19 1 127 my $class = shift;
78 19         45 my($pkt, $parent) = @_;
79 19         35 my $self = {};
80              
81             # Class fields
82              
83 19         40 $self->{_parent} = $parent;
84 19         42 $self->{_frame} = $pkt;
85              
86             # Decode IPv6 packet
87              
88 19 50       46 if (defined($pkt)) {
89             (my $tmp, $self->{len}, my $next_header, $self->{hop_limit},
90 19         124 $self->{src_ip}, $self->{dest_ip}, $self->{data}) = unpack('NnCCa16a16a*', $pkt);
91              
92             # Extract bit fields
93 19         82 $self->{ver} = ($tmp & 0xf0000000) >> 28;
94 19         45 $self->{traffic_class} = ($tmp & 0x0ff00000) >> 20;
95 19         38 $self->{flow_label} = $tmp & 0x000fffff;
96              
97             # truncate data to the length given by the header
98 19         57 $self->{data} = substr $self->{data}, 0, $self->{len};
99              
100             # Decode extension headers
101              
102 19         40 $self->{extheaders} = [];
103 19         57 while (ipv6_extheader($next_header)) {
104 8         19 my $header_type = $next_header;
105 8 100 66     53 last if $header_type == IPv6_EXTHEADER_NONEXT or $header_type == IPv6_EXTHEADER_ESP;
106 6         18 my %header = (type => $header_type);
107 6 50       19 if ($header_type == IPv6_EXTHEADER_FRAGMENT) {
108 0         0 ($next_header, undef, $header{data}, $self->{data}) = unpack('CCa6a*', $self->{data});
109 0         0 $header{len} = 0;
110             } else {
111 6         28 ($next_header, $header{len}, $self->{data}) = unpack('CCa*', $self->{data});
112 6 50       25 my $data_len = $header{len} * ($header_type == IPv6_EXTHEADER_AUTH ? 4 : 8) + 6;
113 6         30 ($header{data}, $self->{data}) = unpack("a${data_len}a*", $self->{data});
114             }
115 6         12 push @{$self->{extheaders}}, \%header;
  6         23  
116             }
117              
118 19         49 $self->{proto} = $next_header;
119              
120             # Convert 128 bit ipv6 addresses to text format
121              
122 19 50       181 $self->{src_ip} = inet_ntop(AF_INET6, $self->{src_ip}) if length($self->{src_ip}) == 16;
123 19 50       106 $self->{dest_ip} = inet_ntop(AF_INET6, $self->{dest_ip}) if length($self->{dest_ip}) == 16;
124             }
125              
126 19         62 return bless $self, $class;
127             }
128              
129             #
130             # Strip header from packet and return the data contained in it
131             #
132              
133             undef &ipv6_strip; # Create ip_strip alias
134             *ipv6_strip = \&strip;
135              
136             sub strip {
137 0     0 1 0 my ($pkt) = @_;
138              
139 0         0 my $ip_obj = NetPacket::IPv6->decode($pkt);
140 0         0 return $ip_obj->{data};
141             }
142              
143             #
144             # Encode a packet
145             #
146              
147             sub encode {
148 7     7 1 40639 my $self = shift;
149              
150             # adjust the length of the packet and pack extension headers
151 7         23 $self->{len} = 0;
152 7         18 my $extheaders = '';
153 7         13 my $next_header = $self->{proto};
154 7         13 foreach my $header (reverse @{$self->{extheaders}}) {
  7         20  
155 3 50       23 if ($header->{type} == IPv6_EXTHEADER_FRAGMENT) {
    50          
    50          
156 0         0 $self->{len} += 8;
157 0         0 $header->{data} = substr $header->{data}, 0, 6;
158 0         0 $header->{len} = 0;
159 0         0 $extheaders = pack('CCa6a*', $next_header, $header->{len}, $header->{data}, $extheaders);
160             } elsif ($header->{type} == IPv6_EXTHEADER_ESP) {
161             # Nothing can follow the encrypted ESP extension header
162 0         0 $self->{data} = $header->{data};
163 0         0 $extheaders = '';
164             } elsif ($header->{type} == IPv6_EXTHEADER_NONEXT) {
165             # Nothing can follow the no-next extension header
166 0         0 $self->{data} = '';
167 0         0 $extheaders = '';
168             } else {
169 3         8 my $data_bytes = length($header->{data});
170 3 50       11 $data_bytes = 6 if $data_bytes < 6;
171 3         10 $self->{len} += $data_bytes + 2;
172 3 50       19 $header->{len} = int(($data_bytes - 6) / ($header->{type} == IPv6_EXTHEADER_AUTH ? 4 : 8));
173 3         27 $extheaders = pack("CCa${data_bytes}a*", $next_header, $header->{len}, $header->{data}, $extheaders);
174             }
175 3         9 $next_header = $header->{type};
176             }
177              
178 7         17 $self->{len} += length($self->{data});
179              
180 7         16 my $tmp = $self->{flow_label} & 0x000fffff;
181 7         18 $tmp |= ($self->{traffic_class} << 20) & 0x0ff00000;
182 7         13 $tmp |= ($self->{ver} << 28) & 0xf0000000;
183              
184             # convert the src and dst ip
185 7         35 my $src_ip = inet_pton(AF_INET6, $self->{src_ip});
186 7         26 my $dest_ip = inet_pton(AF_INET6, $self->{dest_ip});
187              
188 7         42 my $packet = pack('NnCCa16a16', $tmp, $self->{len}, $next_header, $self->{hop_limit}, $src_ip, $dest_ip);
189 7         22 $packet .= $extheaders;
190 7 50       34 $packet .= $self->{data} if defined $self->{data};
191              
192 7         42 return $packet;
193             }
194              
195             sub pseudo_header {
196 5     5 1 11 my $self = shift;
197 5         24 my ($length, $next_header) = @_;
198              
199 5         41 my $src_ip = inet_pton(AF_INET6, $self->{src_ip});
200 5         23 my $dest_ip = inet_pton(AF_INET6, $self->{dest_ip});
201              
202 5         58 return pack('a16a16Na3C', $src_ip, $dest_ip, $length, 0, $next_header);
203             }
204              
205             #
206             # Module initialisation
207             #
208              
209             1;
210              
211             # autoloaded methods go after the END token (&& pod) below
212              
213             =pod
214              
215             =head1 NAME
216              
217             NetPacket::IPv6 - Assemble and disassemble IPv6 (Internet Protocol version 6) packets.
218              
219             =head1 VERSION
220              
221             version 1.7.2
222              
223             =head1 SYNOPSIS
224              
225             use NetPacket::IPv6;
226              
227             $ip_obj = NetPacket::IPv6->decode($raw_pkt);
228             $ip_pkt = NetPacket::IPv6->encode($ip_obj);
229             $ip_data = NetPacket::IPv6::strip($raw_pkt);
230              
231             =head1 DESCRIPTION
232              
233             C provides a set of routines for assembling and
234             disassembling packets using IPv6 (Internet Protocol version 6).
235              
236             =head2 Methods
237              
238             =over
239              
240             =item Cdecode([RAW PACKET])>
241              
242             Decode the raw packet data given and return an object containing
243             instance data. This method will quite happily decode garbage input.
244             It is the responsibility of the programmer to ensure valid packet data
245             is passed to this method.
246              
247             =item Cencode()>
248              
249             Return an IPv6 packet encoded with the instance data specified. This
250             will infer the total length of the packet automatically from the
251             payload length and length of any extension headers.
252              
253             =item Cpseudo_header([PACKET LENGTH], [PROTOCOL])>
254              
255             Return an IPv6 "pseudo-header" suitable for computing checksums for
256             certain upper-level protocols.
257              
258             =back
259              
260             =head2 Functions
261              
262             =over
263              
264             =item C
265              
266             Return the encapsulated data (or payload) contained in the IPv6
267             packet. This data is suitable to be used as input for other
268             C modules.
269              
270             This function is equivalent to creating an object using the
271             C constructor and returning the C field of that
272             object.
273              
274             =item C
275              
276             Return whether the IP protocol type is an IPv6 extension header.
277              
278             =back
279              
280             =head2 Instance data
281              
282             The instance data for the C object consists of
283             the following fields.
284              
285             =over
286              
287             =item ver
288              
289             The IP version number of this packet.
290              
291             =item traffic_class
292              
293             The traffic class of this packet, equivalent to the type-of-service field for
294             IPv4.
295              
296             =item flow_label
297              
298             The flow label of this packet.
299              
300             =item len
301              
302             The payload length (including any extension headers) in bytes for this packet.
303              
304             =item proto
305              
306             The IP protocol number for this packet.
307              
308             =item hop_limit
309              
310             The hop limit for this packet, equivalent to the time-to-live field for IPv4.
311              
312             =item src_ip
313              
314             The source IP address for this packet in colon-separated hextet notation.
315              
316             =item dest_ip
317              
318             The destination IP address for this packet in colon-separated hextet notation.
319              
320             =item extheaders
321              
322             Array of any extension headers for this packet, as a hashref containing the
323             fields described below. An ESP (Encapsulating Security Payload) header will
324             not be represented here; as it and any further extension headers and the
325             payload data will be encrypted, it will be instead represented as the packet
326             payload data itself, with a protocol number of 50 (C).
327              
328             =item data
329              
330             The encapsulated data (payload) for this IPv6 packet.
331              
332             =back
333              
334             Extension headers may contain the following fields.
335              
336             =over
337              
338             =item type
339              
340             The extension header type number.
341              
342             =item len
343              
344             The extension header length, in 8-byte units, minus the first 8-byte unit.
345             (For Authentication extension headers, this length is in 4-byte units, minus
346             the first two 4-byte units.)
347              
348             =item data
349              
350             The remaining contents of the extension header following the next-header and
351             length bytes.
352              
353             =back
354              
355             =head2 Exports
356              
357             =over
358              
359             =item default
360              
361             none
362              
363             =item tags
364              
365             The following tags group together related exportable items.
366              
367             =over
368              
369             =item C<:protos>
370              
371             =item C<:tos>
372              
373             =item C<:misc>
374              
375             Re-exported from L for convenience.
376              
377             =item C<:extheaders>
378              
379             IPv6_EXTHEADER_HOPBYHOP IPv6_EXTHEADER_ROUTING IPv6_EXTHEADER_FRAGMENT
380             IPv6_EXTHEADER_ESP IPv6_EXTHEADER_AUTH IPv6_EXTHEADER_NONEXT IPv6_EXTHEADER_DESTOPT
381             IPv6_EXTHEADER_MOBILITY IPv6_EXTHEADER_HOSTIDENT IPv6_EXTHEADER_SHIM6
382             IPv6_EXTHEADER_TESTING1 IPv6_EXTHEADER_TESTING2
383              
384             =item C<:versions>
385              
386             IP_VERSION_IPv6
387              
388             =item C<:strip>
389              
390             Import the strip function C.
391              
392             =item C<:ALL>
393              
394             All the above exportable items.
395              
396             =back
397              
398             =back
399              
400             =head1 EXAMPLE
401              
402             The following script dumps IPv6 frames by IP address and protocol
403             to standard output.
404              
405             #!/usr/bin/perl -w
406              
407             use strict;
408             use Net::PcapUtils;
409             use NetPacket::Ethernet qw(:strip);
410             use NetPacket::IPv6;
411              
412             sub process_pkt {
413             my ($user, $hdr, $pkt) = @_;
414              
415             my $ip_obj = NetPacket::IPv6->decode(eth_strip($pkt));
416             print("$ip_obj->{src_ip}:$ip_obj->{dest_ip} $ip_obj->{proto}\n");
417             }
418              
419             Net::PcapUtils::loop(\&process_pkt, FILTER => 'ip6');
420              
421             =head1 TODO
422              
423             =over
424              
425             =item More specific keys for well-defined extension headers.
426              
427             =item Parse routing extension headers to correctly compute upper-level checksums.
428              
429             =back
430              
431             =head1 COPYRIGHT
432              
433             Copyright (c) 2018 Dan Book.
434              
435             This module is free software. You can redistribute it and/or
436             modify it under the terms of the Artistic License 2.0.
437              
438             This program is distributed in the hope that it will be useful,
439             but without any warranty; without even the implied warranty of
440             merchantability or fitness for a particular purpose.
441              
442             =head1 AUTHOR
443              
444             Dan Book Edbook@cpan.orgE
445              
446             =cut
447              
448             __END__