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