• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2
3# scapy.contrib.description = OSPF
4# scapy.contrib.status = loads
5
6# This file is part of Scapy
7# Scapy is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 2 of the License, or
10# any later version.
11#
12# Scapy is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with Scapy. If not, see <http://www.gnu.org/licenses/>.
19
20"""
21OSPF extension for Scapy <http://www.secdev.org/scapy>
22
23This module provides Scapy layers for the Open Shortest Path First
24routing protocol as defined in RFC 2328 and RFC 5340.
25
26Copyright (c) 2008 Dirk Loss  :  mail dirk-loss de
27Copyright (c) 2010 Jochen Bartl  :  jochen.bartl gmail com
28"""
29
30
31from scapy.packet import *
32from scapy.fields import *
33from scapy.layers.inet import *
34from scapy.layers.inet6 import *
35from scapy.compat import orb
36
37EXT_VERSION = "v0.9.2"
38
39
40class OSPFOptionsField(FlagsField):
41
42    def __init__(self, name="options", default=0, size=8,
43                 names=None):
44        if names is None:
45            names = ["MT", "E", "MC", "NP", "L", "DC", "O", "DN"]
46        FlagsField.__init__(self, name, default, size, names)
47
48
49_OSPF_types = {1: "Hello",
50               2: "DBDesc",
51               3: "LSReq",
52               4: "LSUpd",
53               5: "LSAck"}
54
55
56class OSPF_Hdr(Packet):
57    name = "OSPF Header"
58    fields_desc = [
59                    ByteField("version", 2),
60                    ByteEnumField("type", 1, _OSPF_types),
61                    ShortField("len", None),
62                    IPField("src", "1.1.1.1"),
63                    IPField("area", "0.0.0.0"), # default: backbone
64                    XShortField("chksum", None),
65                    ShortEnumField("authtype", 0, {0:"Null", 1:"Simple", 2:"Crypto"}),
66                    # Null or Simple Authentication
67                    ConditionalField(XLongField("authdata", 0), lambda pkt:pkt.authtype != 2),
68                    # Crypto Authentication
69                    ConditionalField(XShortField("reserved", 0), lambda pkt:pkt.authtype == 2),
70                    ConditionalField(ByteField("keyid", 1), lambda pkt:pkt.authtype == 2),
71                    ConditionalField(ByteField("authdatalen", 0), lambda pkt:pkt.authtype == 2),
72                    ConditionalField(XIntField("seq", 0), lambda pkt:pkt.authtype == 2),
73                    # TODO: Support authdata (which is appended to the packets as if it were padding)
74                    ]
75
76    def post_build(self, p, pay):
77        # TODO: Remove LLS data from pay
78        # LLS data blocks may be attached to OSPF Hello and DD packets
79        # The length of the LLS block shall not be included into the length of OSPF packet
80        # See <http://tools.ietf.org/html/rfc5613>
81        p += pay
82        l = self.len
83        if l is None:
84            l = len(p)
85            p = p[:2] + struct.pack("!H", l) + p[4:]
86        if self.chksum is None:
87            if self.authtype == 2:
88                ck = 0   # Crypto, see RFC 2328, D.4.3
89            else:
90                # Checksum is calculated without authentication data
91                # Algorithm is the same as in IP()
92                ck = checksum(p[:16] + p[24:])
93                p = p[:12] + struct.pack("!H", ck) + p[14:]
94            # TODO: Handle Crypto: Add message digest  (RFC 2328, D.4.3)
95        return p
96
97    def hashret(self):
98        return struct.pack("H", self.area) + self.payload.hashret()
99
100    def answers(self, other):
101        if (isinstance(other, OSPF_Hdr) and
102            self.area == other.area and
103            self.type == 5):  # Only acknowledgements answer other packets
104                return self.payload.answers(other.payload)
105        return 0
106
107
108class OSPF_Hello(Packet):
109    name = "OSPF Hello"
110    fields_desc = [IPField("mask", "255.255.255.0"),
111                   ShortField("hellointerval", 10),
112                   OSPFOptionsField(),
113                   ByteField("prio", 1),
114                   IntField("deadinterval", 40),
115                   IPField("router", "0.0.0.0"),
116                   IPField("backup", "0.0.0.0"),
117                   FieldListField("neighbors", [], IPField("", "0.0.0.0"), length_from=lambda pkt: (pkt.underlayer.len - 44))]
118
119    def guess_payload_class(self, payload):
120        # check presence of LLS data block flag
121        if self.options & 0x10 == 0x10:
122            return OSPF_LLS_Hdr
123        else:
124            return Packet.guess_payload_class(self, payload)
125
126
127class LLS_Generic_TLV(Packet):
128    name = "LLS Generic"
129    fields_desc = [ShortField("type", 1),
130                   FieldLenField("len", None, length_of=lambda x: x.val),
131                   StrLenField("val", "", length_from=lambda x: x.len)]
132
133    def guess_payload_class(self, p):
134        return conf.padding_layer
135
136
137class LLS_ExtendedOptionsField(FlagsField):
138
139    def __init__(self, name="options", default=0, size=32,
140                 names=None):
141        if names is None:
142            names = ["LR", "RS"]
143        FlagsField.__init__(self, name, default, size, names)
144
145
146class LLS_Extended_Options(LLS_Generic_TLV):
147    name = "LLS Extended Options and Flags"
148    fields_desc = [ShortField("type", 1),
149                   ShortField("len", 4),
150                   LLS_ExtendedOptionsField()]
151
152
153class LLS_Crypto_Auth(LLS_Generic_TLV):
154    name = "LLS Cryptographic Authentication"
155    fields_desc = [ShortField("type", 2),
156                   FieldLenField("len", 20, fmt="B", length_of=lambda x: x.authdata),
157                   XIntField("sequence", b"\x00\x00\x00\x00"),
158                   StrLenField("authdata", b"\x00" * 16, length_from=lambda x: x.len)]
159
160    def post_build(self, p, pay):
161        p += pay
162        l = self.len
163
164        if l is None:
165            # length = len(sequence) + len(authdata) + len(payload)
166            l = len(p[3:])
167            p = p[:2] + struct.pack("!H", l) + p[3:]
168
169        return p
170
171_OSPF_LLSclasses = {1: "LLS_Extended_Options",
172                    2: "LLS_Crypto_Auth"}
173
174
175def _LLSGuessPayloadClass(p, **kargs):
176    """ Guess the correct LLS class for a given payload """
177
178    cls = conf.raw_layer
179    if len(p) >= 4:
180        typ = struct.unpack("!H", p[0:2])[0]
181        clsname = _OSPF_LLSclasses.get(typ, "LLS_Generic_TLV")
182        cls = globals()[clsname]
183    return cls(p, **kargs)
184
185
186class OSPF_LLS_Hdr(Packet):
187    name = "OSPF Link-local signaling"
188    fields_desc = [XShortField("chksum", None),
189                   # FIXME Length should be displayed in 32-bit words
190                   ShortField("len", None),
191                   PacketListField("llstlv", [], _LLSGuessPayloadClass)]
192
193    def post_build(self, p, pay):
194        p += pay
195        l = self.len
196        if l is None:
197            # Length in 32-bit words
198            l = len(p) // 4
199            p = p[:2] + struct.pack("!H", l) + p[4:]
200        if self.chksum is None:
201            c = checksum(p)
202            p = struct.pack("!H", c) + p[2:]
203        return p
204
205_OSPF_LStypes = {1: "router",
206                 2: "network",
207                 3: "summaryIP",
208                 4: "summaryASBR",
209                 5: "external",
210                 7: "NSSAexternal"}
211
212_OSPF_LSclasses = {1: "OSPF_Router_LSA",
213                   2: "OSPF_Network_LSA",
214                   3: "OSPF_SummaryIP_LSA",
215                   4: "OSPF_SummaryASBR_LSA",
216                   5: "OSPF_External_LSA",
217                   7: "OSPF_NSSA_External_LSA"}
218
219
220def ospf_lsa_checksum(lsa):
221    return fletcher16_checkbytes(b"\x00\x00" + lsa[2:], 16) # leave out age
222
223
224class OSPF_LSA_Hdr(Packet):
225    name = "OSPF LSA Header"
226    fields_desc = [ShortField("age", 1),
227                   OSPFOptionsField(),
228                   ByteEnumField("type", 1, _OSPF_LStypes),
229                   IPField("id", "192.168.0.0"),
230                   IPField("adrouter", "1.1.1.1"),
231                   XIntField("seq", 0x80000001),
232                   XShortField("chksum", 0),
233                   ShortField("len", 36)]
234
235    def extract_padding(self, s):
236        return "", s
237
238
239_OSPF_Router_LSA_types = {1: "p2p",
240                          2: "transit",
241                          3: "stub",
242                          4: "virtual"}
243
244
245class OSPF_Link(Packet):
246    name = "OSPF Link"
247    fields_desc = [IPField("id", "192.168.0.0"),
248                   IPField("data", "255.255.255.0"),
249                   ByteEnumField("type", 3, _OSPF_Router_LSA_types),
250                   ByteField("toscount", 0),
251                   ShortField("metric", 10),
252                   # TODO: define correct conditions
253                   ConditionalField(ByteField("tos", 0), lambda pkt: False),
254                   ConditionalField(ByteField("reserved", 0), lambda pkt: False),
255                   ConditionalField(ShortField("tosmetric", 0), lambda pkt: False)]
256
257    def extract_padding(self, s):
258        return "", s
259
260
261def _LSAGuessPayloadClass(p, **kargs):
262    """ Guess the correct LSA class for a given payload """
263    # This is heavily based on scapy-cdp.py by Nicolas Bareil and Arnaud Ebalard
264
265    cls = conf.raw_layer
266    if len(p) >= 4:
267        typ = orb(p[3])
268        clsname = _OSPF_LSclasses.get(typ, "Raw")
269        cls = globals()[clsname]
270    return cls(p, **kargs)
271
272
273class OSPF_BaseLSA(Packet):
274    """ An abstract base class for Link State Advertisements """
275
276    def post_build(self, p, pay):
277        length = self.len
278        if length is None:
279            length = len(p)
280            p = p[:18] + struct.pack("!H", length) + p[20:]
281        if self.chksum is None:
282            chksum = ospf_lsa_checksum(p)
283            p = p[:16] + chksum + p[18:]
284        return p    # p+pay?
285
286    def extract_padding(self, s):
287        length = self.len
288        return "", s
289
290
291class OSPF_Router_LSA(OSPF_BaseLSA):
292    name = "OSPF Router LSA"
293    fields_desc = [ShortField("age", 1),
294                   OSPFOptionsField(),
295                   ByteField("type", 1),
296                   IPField("id", "1.1.1.1"),
297                   IPField("adrouter", "1.1.1.1"),
298                   XIntField("seq", 0x80000001),
299                   XShortField("chksum", None),
300                   ShortField("len", None),
301                   FlagsField("flags", 0, 8, ["B", "E", "V", "W", "Nt"]),
302                   ByteField("reserved", 0),
303                   FieldLenField("linkcount", None, count_of="linklist"),
304                   PacketListField("linklist", [], OSPF_Link,
305                                     count_from=lambda pkt: pkt.linkcount,
306                                     length_from=lambda pkt: pkt.linkcount * 12)]
307
308
309class OSPF_Network_LSA(OSPF_BaseLSA):
310    name = "OSPF Network LSA"
311    fields_desc = [ShortField("age", 1),
312                   OSPFOptionsField(),
313                   ByteField("type", 2),
314                   IPField("id", "192.168.0.0"),
315                   IPField("adrouter", "1.1.1.1"),
316                   XIntField("seq", 0x80000001),
317                   XShortField("chksum", None),
318                   ShortField("len", None),
319                   IPField("mask", "255.255.255.0"),
320                   FieldListField("routerlist", [], IPField("", "1.1.1.1"),
321                                    length_from=lambda pkt: pkt.len - 24)]
322
323
324class OSPF_SummaryIP_LSA(OSPF_BaseLSA):
325    name = "OSPF Summary LSA (IP Network)"
326    fields_desc = [ShortField("age", 1),
327                   OSPFOptionsField(),
328                   ByteField("type", 3),
329                   IPField("id", "192.168.0.0"),
330                   IPField("adrouter", "1.1.1.1"),
331                   XIntField("seq", 0x80000001),
332                   XShortField("chksum", None),
333                   ShortField("len", None),
334                   IPField("mask", "255.255.255.0"),
335                   ByteField("reserved", 0),
336                   X3BytesField("metric", 10),
337                   # TODO: Define correct conditions
338                   ConditionalField(ByteField("tos", 0), lambda pkt:False),
339                   ConditionalField(X3BytesField("tosmetric", 0), lambda pkt:False)]
340
341
342class OSPF_SummaryASBR_LSA(OSPF_SummaryIP_LSA):
343    name = "OSPF Summary LSA (AS Boundary Router)"
344    type = 4
345    id = "2.2.2.2"
346    mask = "0.0.0.0"
347    metric = 20
348
349
350class OSPF_External_LSA(OSPF_BaseLSA):
351    name = "OSPF External LSA (ASBR)"
352    fields_desc = [ShortField("age", 1),
353                   OSPFOptionsField(),
354                   ByteField("type", 5),
355                   IPField("id", "192.168.0.0"),
356                   IPField("adrouter", "2.2.2.2"),
357                   XIntField("seq", 0x80000001),
358                   XShortField("chksum", None),
359                   ShortField("len", None),
360                   IPField("mask", "255.255.255.0"),
361                   FlagsField("ebit", 0, 1, ["E"]),
362                   BitField("reserved", 0, 7),
363                   X3BytesField("metric", 20),
364                   IPField("fwdaddr", "0.0.0.0"),
365                   XIntField("tag", 0),
366                   # TODO: Define correct conditions
367                   ConditionalField(ByteField("tos", 0), lambda pkt:False),
368                   ConditionalField(X3BytesField("tosmetric", 0), lambda pkt:False)]
369
370
371class OSPF_NSSA_External_LSA(OSPF_External_LSA):
372    name = "OSPF NSSA External LSA"
373    type = 7
374
375
376class OSPF_DBDesc(Packet):
377    name = "OSPF Database Description"
378    fields_desc = [ShortField("mtu", 1500),
379                   OSPFOptionsField(),
380                   FlagsField("dbdescr", 0, 8, ["MS", "M", "I", "R", "4", "3", "2", "1"]),
381                   IntField("ddseq", 1),
382                   PacketListField("lsaheaders", None, OSPF_LSA_Hdr,
383                                    count_from = lambda pkt: None,
384                                    length_from = lambda pkt: pkt.underlayer.len - 24 - 8)]
385
386    def guess_payload_class(self, payload):
387        # check presence of LLS data block flag
388        if self.options & 0x10 == 0x10:
389            return OSPF_LLS_Hdr
390        else:
391            return Packet.guess_payload_class(self, payload)
392
393
394class OSPF_LSReq_Item(Packet):
395    name = "OSPF Link State Request (item)"
396    fields_desc = [IntEnumField("type", 1, _OSPF_LStypes),
397                   IPField("id", "1.1.1.1"),
398                   IPField("adrouter", "1.1.1.1")]
399
400    def extract_padding(self, s):
401        return "", s
402
403
404class OSPF_LSReq(Packet):
405    name = "OSPF Link State Request (container)"
406    fields_desc = [PacketListField("requests", None, OSPF_LSReq_Item,
407                                  count_from = lambda pkt:None,
408                                  length_from = lambda pkt:pkt.underlayer.len - 24)]
409
410
411class OSPF_LSUpd(Packet):
412    name = "OSPF Link State Update"
413    fields_desc = [FieldLenField("lsacount", None, fmt="!I", count_of="lsalist"),
414                   PacketListField("lsalist", None, _LSAGuessPayloadClass,
415                                count_from = lambda pkt: pkt.lsacount,
416                                length_from = lambda pkt: pkt.underlayer.len - 24)]
417
418
419class OSPF_LSAck(Packet):
420    name = "OSPF Link State Acknowledgement"
421    fields_desc = [PacketListField("lsaheaders", None, OSPF_LSA_Hdr,
422                                   count_from = lambda pkt: None,
423                                   length_from = lambda pkt: pkt.underlayer.len - 24)]
424
425    def answers(self, other):
426        if isinstance(other, OSPF_LSUpd):
427            for reqLSA in other.lsalist:
428                for ackLSA in self.lsaheaders:
429                    if (reqLSA.type == ackLSA.type and
430                        reqLSA.seq == ackLSA.seq):
431                        return 1
432        return 0
433
434
435#------------------------------------------------------------------------------
436# OSPFv3
437#------------------------------------------------------------------------------
438class OSPFv3_Hdr(Packet):
439    name = "OSPFv3 Header"
440    fields_desc = [ByteField("version", 3),
441                   ByteEnumField("type", 1, _OSPF_types),
442                   ShortField("len", None),
443                   IPField("src", "1.1.1.1"),
444                   IPField("area", "0.0.0.0"),
445                   XShortField("chksum", None),
446                   ByteField("instance", 0),
447                   ByteField("reserved", 0)]
448
449    def post_build(self, p, pay):
450        p += pay
451        l = self.len
452
453        if l is None:
454            l = len(p)
455            p = p[:2] + struct.pack("!H", l) + p[4:]
456
457        if self.chksum is None:
458            chksum = in6_chksum(89, self.underlayer, p)
459            p = p[:12] + struct.pack("!H", chksum) + p[14:]
460
461        return p
462
463
464class OSPFv3OptionsField(FlagsField):
465
466    def __init__(self, name="options", default=0, size=24,
467                 names=None):
468        if names is None:
469            names = ["V6", "E", "MC", "N", "R", "DC", "AF", "L", "I", "F"]
470        FlagsField.__init__(self, name, default, size, names)
471
472
473class OSPFv3_Hello(Packet):
474    name = "OSPFv3 Hello"
475    fields_desc = [IntField("intid", 0),
476                   ByteField("prio", 1),
477                   OSPFv3OptionsField(),
478                   ShortField("hellointerval", 10),
479                   ShortField("deadinterval", 40),
480                   IPField("router", "0.0.0.0"),
481                   IPField("backup", "0.0.0.0"),
482                   FieldListField("neighbors", [], IPField("", "0.0.0.0"),
483                                    length_from=lambda pkt: (pkt.underlayer.len - 36))]
484
485
486_OSPFv3_LStypes = {0x2001: "router",
487                   0x2002: "network",
488                   0x2003: "interAreaPrefix",
489                   0x2004: "interAreaRouter",
490                   0x4005: "asExternal",
491                   0x2007: "type7",
492                   0x0008: "link",
493                   0x2009: "intraAreaPrefix"}
494
495_OSPFv3_LSclasses = {0x2001: "OSPFv3_Router_LSA",
496                     0x2002: "OSPFv3_Network_LSA",
497                     0x2003: "OSPFv3_Inter_Area_Prefix_LSA",
498                     0x2004: "OSPFv3_Inter_Area_Router_LSA",
499                     0x4005: "OSPFv3_AS_External_LSA",
500                     0x2007: "OSPFv3_Type_7_LSA",
501                     0x0008: "OSPFv3_Link_LSA",
502                     0x2009: "OSPFv3_Intra_Area_Prefix_LSA"}
503
504
505class OSPFv3_LSA_Hdr(Packet):
506    name = "OSPFv3 LSA Header"
507    fields_desc = [ShortField("age", 1),
508                   ShortEnumField("type", 0x2001, _OSPFv3_LStypes),
509                   IPField("id", "0.0.0.0"),
510                   IPField("adrouter", "1.1.1.1"),
511                   XIntField("seq", 0x80000001),
512                   XShortField("chksum", 0),
513                   ShortField("len", 36)]
514
515    def extract_padding(self, s):
516        return "", s
517
518
519def _OSPFv3_LSAGuessPayloadClass(p, **kargs):
520    """ Guess the correct OSPFv3 LSA class for a given payload """
521
522    cls = conf.raw_layer
523
524    if len(p) >= 6:
525        typ = struct.unpack("!H", p[2:4])[0]
526        clsname = _OSPFv3_LSclasses.get(typ, "Raw")
527        cls = globals()[clsname]
528
529    return cls(p, **kargs)
530
531
532_OSPFv3_Router_LSA_types = {1: "p2p",
533                            2: "transit",
534                            3: "reserved",
535                            4: "virtual"}
536
537
538class OSPFv3_Link(Packet):
539    name = "OSPFv3 Link"
540    fields_desc = [ByteEnumField("type", 1, _OSPFv3_Router_LSA_types),
541                   ByteField("reserved", 0),
542                   ShortField("metric", 10),
543                   IntField("intid", 0),
544                   IntField("neighintid", 0),
545                   IPField("neighbor", "2.2.2.2")]
546
547    def extract_padding(self, s):
548        return "", s
549
550
551class OSPFv3_Router_LSA(OSPF_BaseLSA):
552    name = "OSPFv3 Router LSA"
553    fields_desc = [ShortField("age", 1),
554                   ShortEnumField("type", 0x2001, _OSPFv3_LStypes),
555                   IPField("id", "0.0.0.0"),
556                   IPField("adrouter", "1.1.1.1"),
557                   XIntField("seq", 0x80000001),
558                   XShortField("chksum", None),
559                   ShortField("len", None),
560                   FlagsField("flags", 0, 8, ["B", "E", "V", "W"]),
561                   OSPFv3OptionsField(),
562                   PacketListField("linklist", [], OSPFv3_Link,
563                                     length_from=lambda pkt:pkt.len - 24)]
564
565
566class OSPFv3_Network_LSA(OSPF_BaseLSA):
567    name = "OSPFv3 Network LSA"
568    fields_desc = [ShortField("age", 1),
569                   ShortEnumField("type", 0x2002, _OSPFv3_LStypes),
570                   IPField("id", "0.0.0.0"),
571                   IPField("adrouter", "1.1.1.1"),
572                   XIntField("seq", 0x80000001),
573                   XShortField("chksum", None),
574                   ShortField("len", None),
575                   ByteField("reserved", 0),
576                   OSPFv3OptionsField(),
577                   FieldListField("routerlist", [], IPField("", "0.0.0.1"),
578                                    length_from=lambda pkt: pkt.len - 24)]
579
580
581class OSPFv3PrefixOptionsField(FlagsField):
582
583    def __init__(self, name="prefixoptions", default=0, size=8,
584                 names=None):
585        if names is None:
586            names = ["NU", "LA", "MC", "P"]
587        FlagsField.__init__(self, name, default, size, names)
588
589
590class OSPFv3_Inter_Area_Prefix_LSA(OSPF_BaseLSA):
591    name = "OSPFv3 Inter Area Prefix LSA"
592    fields_desc = [ShortField("age", 1),
593                   ShortEnumField("type", 0x2003, _OSPFv3_LStypes),
594                   IPField("id", "0.0.0.0"),
595                   IPField("adrouter", "1.1.1.1"),
596                   XIntField("seq", 0x80000001),
597                   XShortField("chksum", None),
598                   ShortField("len", None),
599                   ByteField("reserved", 0),
600                   X3BytesField("metric", 10),
601                   FieldLenField("prefixlen", None, length_of="prefix", fmt="B"),
602                   OSPFv3PrefixOptionsField(),
603                   ShortField("reserved2", 0),
604                   IP6PrefixField("prefix", "2001:db8:0:42::/64", wordbytes=4, length_from=lambda pkt: pkt.prefixlen)]
605
606
607class OSPFv3_Inter_Area_Router_LSA(OSPF_BaseLSA):
608    name = "OSPFv3 Inter Area Router LSA"
609    fields_desc = [ShortField("age", 1),
610                   ShortEnumField("type", 0x2004, _OSPFv3_LStypes),
611                   IPField("id", "0.0.0.0"),
612                   IPField("adrouter", "1.1.1.1"),
613                   XIntField("seq", 0x80000001),
614                   XShortField("chksum", None),
615                   ShortField("len", None),
616                   ByteField("reserved", 0),
617                   OSPFv3OptionsField(),
618                   ByteField("reserved2", 0),
619                   X3BytesField("metric", 1),
620                   IPField("router", "2.2.2.2")]
621
622
623class OSPFv3_AS_External_LSA(OSPF_BaseLSA):
624    name = "OSPFv3 AS External LSA"
625    fields_desc = [ShortField("age", 1),
626                   ShortEnumField("type", 0x4005, _OSPFv3_LStypes),
627                   IPField("id", "0.0.0.0"),
628                   IPField("adrouter", "1.1.1.1"),
629                   XIntField("seq", 0x80000001),
630                   XShortField("chksum", None),
631                   ShortField("len", None),
632                   FlagsField("flags", 0, 8, ["T", "F", "E"]),
633                   X3BytesField("metric", 20),
634                   FieldLenField("prefixlen", None, length_of="prefix", fmt="B"),
635                   OSPFv3PrefixOptionsField(),
636                   ShortEnumField("reflstype", 0, _OSPFv3_LStypes),
637                   IP6PrefixField("prefix", "2001:db8:0:42::/64", wordbytes=4, length_from=lambda pkt: pkt.prefixlen),
638                   ConditionalField(IP6Field("fwaddr", "::"), lambda pkt: pkt.flags & 0x02 == 0x02),
639                   ConditionalField(IntField("tag", 0), lambda pkt: pkt.flags & 0x01 == 0x01),
640                   ConditionalField(IPField("reflsid", 0), lambda pkt: pkt.reflstype != 0)]
641
642
643class OSPFv3_Type_7_LSA(OSPFv3_AS_External_LSA):
644    name = "OSPFv3 Type 7 LSA"
645    type = 0x2007
646
647
648class OSPFv3_Prefix_Item(Packet):
649    name = "OSPFv3 Link Prefix Item"
650    fields_desc = [FieldLenField("prefixlen", None, length_of="prefix", fmt="B"),
651                   OSPFv3PrefixOptionsField(),
652                   ShortField("metric", 10),
653                   IP6PrefixField("prefix", "2001:db8:0:42::/64", wordbytes=4, length_from=lambda pkt: pkt.prefixlen)]
654
655    def extract_padding(self, s):
656        return "", s
657
658
659class OSPFv3_Link_LSA(OSPF_BaseLSA):
660    name = "OSPFv3 Link LSA"
661    fields_desc = [ShortField("age", 1),
662                   ShortEnumField("type", 0x0008, _OSPFv3_LStypes),
663                   IPField("id", "0.0.0.0"),
664                   IPField("adrouter", "1.1.1.1"),
665                   XIntField("seq", 0x80000001),
666                   XShortField("chksum", None),
667                   ShortField("len", None),
668                   ByteField("prio", 1),
669                   OSPFv3OptionsField(),
670                   IP6Field("lladdr", "fe80::"),
671                   FieldLenField("prefixes", None, count_of="prefixlist", fmt="I"),
672                   PacketListField("prefixlist", None, OSPFv3_Prefix_Item,
673                                  count_from = lambda pkt: pkt.prefixes)]
674
675
676class OSPFv3_Intra_Area_Prefix_LSA(OSPF_BaseLSA):
677    name = "OSPFv3 Intra Area Prefix LSA"
678    fields_desc = [ShortField("age", 1),
679                   ShortEnumField("type", 0x2009, _OSPFv3_LStypes),
680                   IPField("id", "0.0.0.0"),
681                   IPField("adrouter", "1.1.1.1"),
682                   XIntField("seq", 0x80000001),
683                   XShortField("chksum", None),
684                   ShortField("len", None),
685                   FieldLenField("prefixes", None, count_of="prefixlist", fmt="H"),
686                   ShortEnumField("reflstype", 0, _OSPFv3_LStypes),
687                   IPField("reflsid", "0.0.0.0"),
688                   IPField("refadrouter", "0.0.0.0"),
689                   PacketListField("prefixlist", None, OSPFv3_Prefix_Item,
690                                  count_from = lambda pkt: pkt.prefixes)]
691
692
693class OSPFv3_DBDesc(Packet):
694    name = "OSPFv3 Database Description"
695    fields_desc = [ByteField("reserved", 0),
696                   OSPFv3OptionsField(),
697                   ShortField("mtu", 1500),
698                   ByteField("reserved2", 0),
699                   FlagsField("dbdescr", 0, 8, ["MS", "M", "I", "R"]),
700                   IntField("ddseq", 1),
701                   PacketListField("lsaheaders", None, OSPFv3_LSA_Hdr,
702                                    count_from = lambda pkt:None,
703                                    length_from = lambda pkt:pkt.underlayer.len - 28)]
704
705
706class OSPFv3_LSReq_Item(Packet):
707    name = "OSPFv3 Link State Request (item)"
708    fields_desc = [ShortField("reserved", 0),
709                   ShortEnumField("type", 0x2001, _OSPFv3_LStypes),
710                   IPField("id", "1.1.1.1"),
711                   IPField("adrouter", "1.1.1.1")]
712
713    def extract_padding(self, s):
714        return "", s
715
716
717class OSPFv3_LSReq(Packet):
718    name = "OSPFv3 Link State Request (container)"
719    fields_desc = [PacketListField("requests", None, OSPFv3_LSReq_Item,
720                                  count_from = lambda pkt:None,
721                                  length_from = lambda pkt:pkt.underlayer.len - 16)]
722
723
724class OSPFv3_LSUpd(Packet):
725    name = "OSPFv3 Link State Update"
726    fields_desc = [FieldLenField("lsacount", None, fmt="!I", count_of="lsalist"),
727                   PacketListField("lsalist", [], _OSPFv3_LSAGuessPayloadClass,
728                                count_from = lambda pkt:pkt.lsacount,
729                                length_from = lambda pkt:pkt.underlayer.len - 16)]
730
731
732class OSPFv3_LSAck(Packet):
733    name = "OSPFv3 Link State Acknowledgement"
734    fields_desc = [PacketListField("lsaheaders", None, OSPFv3_LSA_Hdr,
735                                   count_from = lambda pkt:None,
736                                   length_from = lambda pkt:pkt.underlayer.len - 16)]
737
738
739bind_layers(IP, OSPF_Hdr, proto=89)
740bind_layers(OSPF_Hdr, OSPF_Hello, type=1)
741bind_layers(OSPF_Hdr, OSPF_DBDesc, type=2)
742bind_layers(OSPF_Hdr, OSPF_LSReq, type=3)
743bind_layers(OSPF_Hdr, OSPF_LSUpd, type=4)
744bind_layers(OSPF_Hdr, OSPF_LSAck, type=5)
745DestIPField.bind_addr(OSPF_Hdr, "224.0.0.5")
746
747bind_layers(IPv6, OSPFv3_Hdr, nh=89)
748bind_layers(OSPFv3_Hdr, OSPFv3_Hello, type=1)
749bind_layers(OSPFv3_Hdr, OSPFv3_DBDesc, type=2)
750bind_layers(OSPFv3_Hdr, OSPFv3_LSReq, type=3)
751bind_layers(OSPFv3_Hdr, OSPFv3_LSUpd, type=4)
752bind_layers(OSPFv3_Hdr, OSPFv3_LSAck, type=5)
753DestIP6Field.bind_addr(OSPFv3_Hdr, "ff02::5")
754
755
756if __name__ == "__main__":
757    from scapy.main import interact
758    interact(mydict=globals(), mybanner="OSPF extension %s" % EXT_VERSION)
759