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