File Coverage

blib/lib/Net/Frame/Layer/OSPF.pm
Criterion Covered Total %
statement 141 203 69.4
branch 6 54 11.1
condition 1 30 3.3
subroutine 42 48 87.5
pod 9 9 100.0
total 199 344 57.8


line stmt bran cond sub pod time code
1             #
2             # $Id: OSPF.pm 73 2015-01-14 06:42:49Z gomor $
3             #
4             package Net::Frame::Layer::OSPF;
5 14     14   18948 use strict; use warnings;
  14     14   24  
  14         581  
  14         70  
  14         24  
  14         846  
6              
7             our $VERSION = '1.01';
8              
9 14     14   6256 use Net::Frame::Layer qw(:consts :subs);
  14         3628836  
  14         3787  
10             require Exporter;
11             our @ISA = qw(Net::Frame::Layer Exporter);
12              
13             our %EXPORT_TAGS = (
14             consts => [qw(
15             NF_OSPF_HDR_LEN
16             NF_OSPF_TYPE_HELLO
17             NF_OSPF_TYPE_DATABASEDESC
18             NF_OSPF_TYPE_LINKSTATEREQUEST
19             NF_OSPF_TYPE_LINKSTATEUPDATE
20             NF_OSPF_TYPE_LINKSTATEACK
21             NF_OSPF_AUTHTYPE_NULL
22             NF_OSPF_AUTHTYPE_SIMPLE
23             NF_OSPF_AUTHTYPE_CRYPTO
24             NF_OSPF_LSA_HDR_LEN
25             NF_OSPF_LSTYPE_ROUTER
26             NF_OSPF_LSTYPE_NETWORK
27             NF_OSPF_LSTYPE_SUMMARYIP
28             NF_OSPF_LSTYPE_SUMMARYASBR
29             NF_OSPF_LSTYPE_ASEXTERNAL
30             NF_OSPF_LSTYPE_OPAQUELINKLOCAL
31             NF_OSPF_LSTYPE_OPAQUEAREALOCAL
32             NF_OSPF_LSTYPE_OPAQUEDOMAIN
33             NF_OSPF_HELLO_OPTIONS_UNK
34             NF_OSPF_HELLO_OPTIONS_E
35             NF_OSPF_HELLO_OPTIONS_MC
36             NF_OSPF_HELLO_OPTIONS_NP
37             NF_OSPF_HELLO_OPTIONS_EA
38             NF_OSPF_HELLO_OPTIONS_DC
39             NF_OSPF_HELLO_OPTIONS_O
40             NF_OSPF_HELLO_OPTIONS_DN
41             NF_OSPF_DATABASEDESC_OPTIONS_DN
42             NF_OSPF_DATABASEDESC_OPTIONS_0
43             NF_OSPF_DATABASEDESC_OPTIONS_DC
44             NF_OSPF_DATABASEDESC_OPTIONS_L
45             NF_OSPF_DATABASEDESC_OPTIONS_NP
46             NF_OSPF_DATABASEDESC_OPTIONS_MC
47             NF_OSPF_DATABASEDESC_OPTIONS_E
48             NF_OSPF_DATABASEDESC_FLAGS_MS
49             NF_OSPF_DATABASEDESC_FLAGS_M
50             NF_OSPF_DATABASEDESC_FLAGS_I
51             )],
52             );
53             our @EXPORT_OK = (
54             @{$EXPORT_TAGS{consts}},
55             );
56              
57 14     14   87 use constant NF_OSPF_HDR_LEN => 24;
  14         22  
  14         1020  
58 14     14   72 use constant NF_OSPF_LSA_HDR_LEN => 20;
  14         23  
  14         635  
59              
60 14     14   72 use constant NF_OSPF_TYPE_HELLO => 0x01;
  14         27  
  14         758  
61 14     14   67 use constant NF_OSPF_TYPE_DATABASEDESC => 0x02;
  14         18  
  14         762  
62 14     14   63 use constant NF_OSPF_TYPE_LINKSTATEREQUEST => 0x03;
  14         21  
  14         595  
63 14     14   61 use constant NF_OSPF_TYPE_LINKSTATEUPDATE => 0x04;
  14         18  
  14         592  
64 14     14   69 use constant NF_OSPF_TYPE_LINKSTATEACK => 0x05;
  14         17  
  14         563  
65              
66 14     14   57 use constant NF_OSPF_AUTHTYPE_NULL => 0x0000;
  14         17  
  14         547  
67 14     14   57 use constant NF_OSPF_AUTHTYPE_SIMPLE => 0x0001;
  14         19  
  14         607  
68 14     14   62 use constant NF_OSPF_AUTHTYPE_CRYPTO => 0x0002;
  14         20  
  14         633  
69              
70 14     14   76 use constant NF_OSPF_LSTYPE_ROUTER => 0x01;
  14         28  
  14         656  
71 14     14   66 use constant NF_OSPF_LSTYPE_NETWORK => 0x02;
  14         16  
  14         642  
72 14     14   62 use constant NF_OSPF_LSTYPE_SUMMARYIP => 0x03;
  14         17  
  14         554  
73 14     14   55 use constant NF_OSPF_LSTYPE_SUMMARYASBR => 0x04;
  14         19  
  14         531  
74 14     14   56 use constant NF_OSPF_LSTYPE_ASEXTERNAL => 0x05;
  14         18  
  14         528  
75 14     14   60 use constant NF_OSPF_LSTYPE_OPAQUELINKLOCAL => 0x0a;
  14         17  
  14         578  
76 14     14   56 use constant NF_OSPF_LSTYPE_OPAQUEAREALOCAL => 0x0b;
  14         23  
  14         609  
77 14     14   65 use constant NF_OSPF_LSTYPE_OPAQUEDOMAIN => 0x0c;
  14         18  
  14         606  
78              
79 14     14   63 use constant NF_OSPF_HELLO_OPTIONS_UNK => 0x01; # Not in RFC 2328
  14         21  
  14         530  
80 14     14   91 use constant NF_OSPF_HELLO_OPTIONS_E => 0x02;
  14         19  
  14         554  
81 14     14   54 use constant NF_OSPF_HELLO_OPTIONS_MC => 0x04;
  14         25  
  14         524  
82 14     14   60 use constant NF_OSPF_HELLO_OPTIONS_NP => 0x08;
  14         15  
  14         528  
83 14     14   59 use constant NF_OSPF_HELLO_OPTIONS_EA => 0x10;
  14         16  
  14         534  
84 14     14   57 use constant NF_OSPF_HELLO_OPTIONS_DC => 0x20;
  14         17  
  14         561  
85 14     14   214 use constant NF_OSPF_HELLO_OPTIONS_O => 0x40; # Not in RFC 2328
  14         21  
  14         2128  
86 14     14   75 use constant NF_OSPF_HELLO_OPTIONS_DN => 0x80; # Not in RFC 2328
  14         738  
  14         3430  
87              
88 14     14   69 use constant NF_OSPF_DATABASEDESC_OPTIONS_DN => 0x01;
  14         17  
  14         4374  
89 14     14   1001 use constant NF_OSPF_DATABASEDESC_OPTIONS_0 => 0x02;
  14         27  
  14         560  
90 14     14   60 use constant NF_OSPF_DATABASEDESC_OPTIONS_DC => 0x04;
  14         16  
  14         557  
91 14     14   60 use constant NF_OSPF_DATABASEDESC_OPTIONS_L => 0x08;
  14         21  
  14         583  
92 14     14   816 use constant NF_OSPF_DATABASEDESC_OPTIONS_NP => 0x10;
  14         17  
  14         588  
93 14     14   63 use constant NF_OSPF_DATABASEDESC_OPTIONS_MC => 0x20;
  14         29  
  14         536  
94 14     14   92 use constant NF_OSPF_DATABASEDESC_OPTIONS_E => 0x40;
  14         18  
  14         610  
95              
96 14     14   68 use constant NF_OSPF_DATABASEDESC_FLAGS_MS => 0x01;
  14         15  
  14         570  
97 14     14   57 use constant NF_OSPF_DATABASEDESC_FLAGS_M => 0x02;
  14         16  
  14         608  
98 14     14   57 use constant NF_OSPF_DATABASEDESC_FLAGS_I => 0x04;
  14         14  
  14         15919  
99              
100             our @AS = qw(
101             version
102             type
103             length
104             routerId
105             areaId
106             checksum
107             authType
108             authData
109             packet
110             );
111             __PACKAGE__->cgBuildIndices;
112             __PACKAGE__->cgBuildAccessorsScalar(\@AS);
113              
114             require Net::Frame::Layer::OSPF::Hello;
115             require Net::Frame::Layer::OSPF::DatabaseDesc;
116             require Net::Frame::Layer::OSPF::LinkStateUpdate;
117             require Net::Frame::Layer::OSPF::LinkStateRequest;
118             require Net::Frame::Layer::OSPF::LinkStateAck;
119             require Net::Frame::Layer::OSPF::Lls;
120              
121             sub new {
122             shift->SUPER::new(
123 1     1 1 19 version => 2,
124             type => 0,
125             length => NF_OSPF_HDR_LEN,
126             routerId => '127.0.0.1',
127             areaId => '127.0.0.1',
128             checksum => 0,
129             authType => NF_OSPF_AUTHTYPE_NULL,
130             authData => "0000000000000000",
131             @_,
132             );
133             }
134              
135             sub match {
136 0     0 1 0 my $self = shift;
137 0         0 my ($with) = @_;
138 0 0 0     0 if ($self->packet && $with->packet) {
139 0         0 my $s = $self->packet->layer;
140 0         0 my $sHdr = $self->packet;
141 0         0 my $w = $with->packet->layer;
142 0         0 my $wHdr = $with->packet;
143 0 0 0     0 if (($s eq 'OSPF::Hello') && ($w eq 'OSPF::DatabaseDesc')) {
    0 0        
    0 0        
144 0         0 return 1;
145             }
146             elsif (($s eq 'OSPF::DatabaseDesc') && ($w eq 'OSPF::DatabaseDesc')) {
147 0 0 0     0 if ($sHdr->flags == 0x07 && $wHdr->flags == 0x02) {
    0 0        
    0 0        
148 0         0 return 1;
149             }
150             elsif ($sHdr->flags == 0x03 && $wHdr->flags == 0x00) {
151 0         0 return 1;
152             }
153             elsif ($sHdr->flags == 0x01 && $wHdr->flags == 0x00) {
154 0         0 return 1;
155             }
156             }
157             elsif (($s eq 'OSPF::LinkStateRequest')
158             && ($w eq 'OSPF::LinkStateRequest')) {
159 0         0 return 1;
160             }
161             }
162 0         0 0;
163             }
164              
165 0     0 1 0 sub getLength { shift->length }
166              
167             sub computeLengths {
168 0     0 1 0 my $self = shift;
169 0         0 my $len = $self->getLength;
170              
171             # If packet is not a ref, it is not an object, but a raw data (LinkStateAck)
172 0 0 0     0 if ($self->packet && ! ref($self->packet)) {
    0          
173 0         0 $len += length($self->packet);
174             }
175             # Else, standard object
176             elsif ($self->packet) {
177 0         0 $len += $self->packet->getLength;
178             }
179 0         0 $self->length($len);
180             }
181              
182             sub computeChecksums {
183 0     0 1 0 my $self = shift;
184              
185             # When simple password auth is used, we MUST calculate
186             # the checksum without the plaintext password
187 0         0 my $authData = $self->authData;
188 0         0 $self->authData("0000000000000000");
189              
190 0         0 $self->checksum(0);
191 0         0 $self->checksum(inetChecksum($self->pack));
192              
193             # Restore the simple password
194 0         0 $self->authData($authData);
195             }
196              
197             sub pack {
198 1     1 1 248 my $self = shift;
199              
200 1 50       4 my $raw = $self->SUPER::pack('CCna4a4nnH16',
201             $self->version, $self->type, $self->length,
202             inetAton($self->routerId), inetAton($self->areaId),
203             $self->checksum, $self->authType, $self->authData,
204             ) or return undef;
205              
206 1 50 33     96 if ($self->packet && ref($self->packet)) {
    50          
207 0         0 $raw .= $self->packet->pack;
208             }
209             elsif ($self->packet) {
210 0         0 $raw .= $self->packet;
211             }
212              
213 1         22 $self->raw($raw);
214             }
215              
216             sub unpack {
217 1     1 1 12 my $self = shift;
218              
219 1 50       3 my ($version, $type, $length, $routerId, $areaId, $checksum,
220             $authType, $authData, $payload) =
221             $self->SUPER::unpack('CCna4a4nnH16 a*', $self->raw)
222             or return undef;
223              
224 1         28 $self->version($version);
225 1         8 $self->type($type);
226 1         7 $self->length($length);
227 1         8 $self->routerId(inetNtoa($routerId));
228 1         12 $self->areaId(inetNtoa($areaId));
229 1         9 $self->checksum($checksum);
230 1         6 $self->authType($authType);
231 1         8 $self->authData($authData);
232              
233 1         6 my $keep = $length - NF_OSPF_HDR_LEN;
234 1         2 my $tail = substr($payload, 0, $keep);
235 1         2 $payload = substr($payload, $keep);
236              
237             # Handle type of OSPF frame
238 1         2 my $next;
239 1 50       3 if ($tail) {
240 0 0       0 if ($type == NF_OSPF_TYPE_HELLO) {
    0          
    0          
    0          
    0          
241 0         0 $next = Net::Frame::Layer::OSPF::Hello->new(raw => $tail);
242             }
243             elsif ($type == NF_OSPF_TYPE_DATABASEDESC) {
244 0         0 $next = Net::Frame::Layer::OSPF::DatabaseDesc->new(raw => $tail);
245             }
246             elsif ($type == NF_OSPF_TYPE_LINKSTATEUPDATE) {
247 0         0 $next = Net::Frame::Layer::OSPF::LinkStateUpdate->new(raw => $tail);
248             }
249             elsif ($type == NF_OSPF_TYPE_LINKSTATEREQUEST) {
250 0         0 $next = Net::Frame::Layer::OSPF::LinkStateRequest->new(raw => $tail);
251             }
252             elsif ($type == NF_OSPF_TYPE_LINKSTATEACK) {
253 0         0 $next = Net::Frame::Layer::OSPF::LinkStateAck->new(raw => $tail);
254             }
255             }
256              
257 1 50       3 if ($next) {
258 0         0 $next->unpack;
259 0         0 my $newPayload = $next->payload;
260 0 0       0 if ($payload) { $newPayload .= $payload }
  0         0  
261 0         0 $next->payload($newPayload);
262 0         0 $self->packet($next);
263 0         0 $payload = $next->payload;
264              
265 0 0       0 if ($payload) {
266             # Handle special options for OSPF::Hello frame
267 0 0       0 if ($next->layer eq 'OSPF::Hello') {
    0          
268 0 0       0 if ($next->options & NF_OSPF_HELLO_OPTIONS_EA) {
269 0         0 my $lls = Net::Frame::Layer::OSPF::Lls->new(raw => $payload);
270 0         0 $lls->unpack;
271 0         0 $next->lls($lls);
272 0         0 $payload = $lls->payload;
273             }
274             }
275             # Handle special options for OSPF::DatabaseDesc frame
276             elsif ($next->layer eq 'OSPF::DatabaseDesc') {
277             # XXX: ugly hack, should rework
278 0 0       0 if ($next->options == 0x52) {
279 0         0 my $lls = Net::Frame::Layer::OSPF::Lls->new(raw => $payload);
280 0         0 $lls->unpack;
281 0         0 $next->lls($lls);
282 0         0 $payload = $lls->payload;
283             }
284             }
285             }
286             }
287             else {
288 1         2 $payload = $tail.$payload;
289             }
290              
291 1         6 $self->payload($payload);
292              
293 1         16 $self;
294             }
295              
296 0     0 1   sub encapsulate { shift->nextLayer }
297              
298             sub print {
299 0     0 1   my $self = shift;
300              
301 0           my $l = $self->layer;
302 0           my $buf = sprintf "$l: version:%d type:0x%02x length:%d\n".
303             "$l: routerId:%s areaId:%s\n".
304             "$l: checksum:0x%04x authType:0x%04x\n".
305             "$l: authData:%s",
306             $self->version, $self->type, $self->length,
307             $self->routerId, $self->areaId, $self->checksum,
308             $self->authType, $self->authData;
309              
310 0 0 0       if ($self->packet && ref($self->packet)) {
311 0           $buf .= "\n".$self->packet->print;
312             }
313              
314 0           $buf;
315             }
316              
317             1;
318              
319             __END__