Home | History | Annotate | Download | only in contrib
      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 """
     21 OSPF extension for Scapy <http://www.secdev.org/scapy>
     22 
     23 This module provides Scapy layers for the Open Shortest Path First
     24 routing protocol as defined in RFC 2328 and RFC 5340.
     25 
     26 Copyright (c) 2008 Dirk Loss  :  mail dirk-loss de
     27 Copyright (c) 2010 Jochen Bartl  :  jochen.bartl gmail com
     28 """
     29 
     30 
     31 from scapy.packet import *
     32 from scapy.fields import *
     33 from scapy.layers.inet import *
     34 from scapy.layers.inet6 import *
     35 from scapy.compat import orb
     36 
     37 EXT_VERSION = "v0.9.2"
     38 
     39 
     40 class 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 
     56 class 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 
    108 class 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 
    127 class 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 
    137 class 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 
    146 class 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 
    153 class 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 
    175 def _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 
    186 class 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 
    220 def ospf_lsa_checksum(lsa):
    221     return fletcher16_checkbytes(b"\x00\x00" + lsa[2:], 16) # leave out age
    222 
    223 
    224 class 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 
    245 class 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 
    261 def _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 
    273 class 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 
    291 class 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 
    309 class 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 
    324 class 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 
    342 class 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 
    350 class 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 
    371 class OSPF_NSSA_External_LSA(OSPF_External_LSA):
    372     name = "OSPF NSSA External LSA"
    373     type = 7
    374 
    375 
    376 class 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 
    394 class 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 
    404 class 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 
    411 class 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 
    419 class 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 #------------------------------------------------------------------------------
    438 class 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 
    464 class 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 
    473 class 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 
    505 class 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 
    519 def _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 
    538 class 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 
    551 class 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 
    566 class 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 
    581 class 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 
    590 class 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 
    607 class 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 
    623 class 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 
    643 class OSPFv3_Type_7_LSA(OSPFv3_AS_External_LSA):
    644     name = "OSPFv3 Type 7 LSA"
    645     type = 0x2007
    646 
    647 
    648 class 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 
    659 class 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 
    676 class 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 
    693 class 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 
    706 class 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 
    717 class 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 
    724 class 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 
    732 class 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 
    739 bind_layers(IP, OSPF_Hdr, proto=89)
    740 bind_layers(OSPF_Hdr, OSPF_Hello, type=1)
    741 bind_layers(OSPF_Hdr, OSPF_DBDesc, type=2)
    742 bind_layers(OSPF_Hdr, OSPF_LSReq, type=3)
    743 bind_layers(OSPF_Hdr, OSPF_LSUpd, type=4)
    744 bind_layers(OSPF_Hdr, OSPF_LSAck, type=5)
    745 DestIPField.bind_addr(OSPF_Hdr, "224.0.0.5")
    746 
    747 bind_layers(IPv6, OSPFv3_Hdr, nh=89)
    748 bind_layers(OSPFv3_Hdr, OSPFv3_Hello, type=1)
    749 bind_layers(OSPFv3_Hdr, OSPFv3_DBDesc, type=2)
    750 bind_layers(OSPFv3_Hdr, OSPFv3_LSReq, type=3)
    751 bind_layers(OSPFv3_Hdr, OSPFv3_LSUpd, type=4)
    752 bind_layers(OSPFv3_Hdr, OSPFv3_LSAck, type=5)
    753 DestIP6Field.bind_addr(OSPFv3_Hdr, "ff02::5")
    754 
    755 
    756 if __name__ == "__main__":
    757     from scapy.main import interact
    758     interact(mydict=globals(), mybanner="OSPF extension %s" % EXT_VERSION)
    759