1 # This file is part of Scapy 2 # Scapy is free software: you can redistribute it and/or modify 3 # it under the terms of the GNU General Public License as published by 4 # the Free Software Foundation, either version 2 of the License, or 5 # any later version. 6 # 7 # Scapy is distributed in the hope that it will be useful, 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 # GNU General Public License for more details. 11 # 12 # You should have received a copy of the GNU General Public License 13 # along with Scapy. If not, see <http://www.gnu.org/licenses/>. 14 15 # scapy.contrib.description = ISIS 16 # scapy.contrib.status = loads 17 18 """ 19 IS-IS Scapy Extension 20 ~~~~~~~~~~~~~~~~~~~~~ 21 22 :copyright: 2014-2016 BENOCS GmbH, Berlin (Germany) 23 :author: Marcel Patzlaff, mpatzlaff (at] benocs.com 24 Michal Kaliszan, mkaliszan (at] benocs.com 25 :license: GPLv2 26 27 This module is free software; you can redistribute it and/or 28 modify it under the terms of the GNU General Public License 29 as published by the Free Software Foundation; either version 2 30 of the License, or (at your option) any later version. 31 32 This module is distributed in the hope that it will be useful, 33 but WITHOUT ANY WARRANTY; without even the implied warranty of 34 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 35 GNU General Public License for more details. 36 37 :description: 38 39 This module provides Scapy layers for the Intermediate System 40 to Intermediate System routing protocol as defined in RFC 1195. 41 42 Currently it (partially) supports the packaging/encoding 43 requirements of the following RFCs: 44 * RFC 1195 (only the TCP/IP related part) 45 * RFC 3358 (optional checksums) 46 * RFC 5301 (dynamic hostname extension) 47 * RFC 5302 (domain-wide prefix distribution) 48 * RFC 5303 (three-way handshake) 49 * RFC 5304 (cryptographic authentication) 50 * RFC 5308 (routing IPv6 with IS-IS) 51 52 :TODO: 53 54 - packet relations (requests, responses) 55 - support for recent RFCs: 56 * RFC 5305 (traffic engineering) 57 * RFC 5307 (support for G-MPLS) 58 * RFC 5310 (generic cryptographic authentication) 59 * RFC 5316 (inter-AS MPLS and G-MPLS TE) 60 61 """ 62 63 from __future__ import absolute_import 64 import struct 65 import random 66 67 from scapy.config import conf 68 from scapy.fields import * 69 from scapy.packet import * 70 from scapy.layers.clns import network_layer_protocol_ids, register_cln_protocol 71 from scapy.layers.inet6 import IP6ListField, IP6Field 72 from scapy.utils import fletcher16_checkbytes 73 from scapy.volatile import RandString, RandByte 74 import random 75 from scapy.modules.six.moves import range 76 from scapy.compat import raw 77 78 EXT_VERSION = "v0.0.2" 79 80 conf.debug_dissector = True 81 82 83 ####################################################################### 84 ## ISIS Utilities + Fields ## 85 ####################################################################### 86 def isis_area2str(area): 87 return b"".join(hex_bytes(x) for x in area.split(".")) 88 89 90 def isis_str2area(s): 91 if len(s) == 0: 92 return "" 93 94 numbytes = len(s[1:]) 95 fmt = "%02X" + (".%02X%02X" * (numbytes // 2)) + ("" if (numbytes % 2) == 0 else ".%02X") 96 return fmt % tuple(orb(x) for x in s) 97 98 99 def isis_sysid2str(sysid): 100 return b"".join(hex_bytes(x) for x in sysid.split(".")) 101 102 103 def isis_str2sysid(s): 104 return ("%02X%02X."*3)[:-1] % tuple(orb(x) for x in s) 105 106 107 def isis_nodeid2str(nodeid): 108 return isis_sysid2str(nodeid[:-3]) + hex_bytes(nodeid[-2:]) 109 110 111 def isis_str2nodeid(s): 112 return "%s.%02X" % (isis_str2sysid(s[:-1]), orb(s[-1])) 113 114 115 def isis_lspid2str(lspid): 116 return isis_nodeid2str(lspid[:-3]) + hex_bytes(lspid[-2:]) 117 118 119 def isis_str2lspid(s): 120 return "%s-%02X" % (isis_str2nodeid(s[:-1]), orb(s[-1])) 121 122 123 class _ISIS_IdFieldBase(Field): 124 __slots__ = ["to_str", "to_id", "length"] 125 def __init__(self, name, default, length, to_str, to_id): 126 self.to_str = to_str 127 self.to_id = to_id 128 self.length = length 129 Field.__init__(self, name, default, "%is" % length) 130 131 def i2m(self, pkt, x): 132 if x is None: 133 return b"\0"*self.length 134 135 return self.to_str(x) 136 137 def m2i(self, pkt, x): 138 return self.to_id(x) 139 140 def any2i(self, pkt, x): 141 if isinstance(x, str) and len(x) == self.length: 142 return self.m2i(pkt, x) 143 144 return x 145 146 147 class _ISIS_RandId(RandString): 148 def __init__(self, template): 149 self.bytecount = template.count("*") 150 self.format = template.replace("*", "%02X") 151 152 def _fix(self): 153 if self.bytecount == 0: 154 return "" 155 156 val = () 157 158 for _ in range(self.bytecount): 159 val += (RandByte(),) 160 161 return self.format % val 162 163 164 class _ISIS_RandAreaId(_ISIS_RandId): 165 def __init__(self, bytecount= None): 166 self.bytecount = random.randint(1, 13) if bytecount is None else bytecount 167 self.format = "%02X" + (".%02X%02X" * ((self.bytecount-1) // 2)) + ("" if ((self.bytecount-1) % 2) == 0 else ".%02X") 168 169 170 class ISIS_AreaIdField(Field): 171 __slots__ = ["length_from"] 172 173 def __init__(self, name, default, length_from): 174 Field.__init__(self, name, default) 175 self.length_from = length_from 176 177 def i2m(self, pkt, x): 178 return isis_area2str(x) 179 180 def m2i(self, pkt, x): 181 return isis_str2area(x) 182 183 def i2len(self, pkt, x): 184 if x is None: 185 return 0 186 l = len(x) 187 # l/5 is the number of dots in the Area ID 188 return (l - (l // 5)) // 2 189 190 def addfield(self, pkt, s, val): 191 sval = self.i2m(pkt, val) 192 return s+struct.pack("!%is" % len(sval), sval) 193 194 def getfield(self, pkt, s): 195 numbytes = self.length_from(pkt) 196 return s[numbytes:], self.m2i(pkt, struct.unpack("!%is" % numbytes, s[:numbytes])[0]) 197 198 def randval(self): 199 return _ISIS_RandAreaId() 200 201 202 class ISIS_SystemIdField(_ISIS_IdFieldBase): 203 def __init__(self, name, default): 204 _ISIS_IdFieldBase.__init__(self, name, default, 6, isis_sysid2str, isis_str2sysid) 205 206 def randval(self): 207 return _ISIS_RandId("**.**.**") 208 209 210 class ISIS_NodeIdField(_ISIS_IdFieldBase): 211 def __init__(self, name, default): 212 _ISIS_IdFieldBase.__init__(self, name, default, 7, isis_nodeid2str, isis_str2nodeid) 213 214 def randval(self): 215 return _ISIS_RandId("**.**.**.*") 216 217 218 class ISIS_LspIdField(_ISIS_IdFieldBase): 219 def __init__(self, name, default): 220 _ISIS_IdFieldBase.__init__(self, name, default, 8, isis_lspid2str, isis_str2lspid) 221 222 def randval(self): 223 return _ISIS_RandId("**.**.**.*-*") 224 225 226 class ISIS_CircuitTypeField(FlagsField): 227 def __init__(self, name="circuittype", default=2, size=8, 228 names=None): 229 if names is None: 230 names = ["L1", "L2", "r0", "r1", "r2", "r3", "r4", "r5"] 231 FlagsField.__init__(self, name, default, size, names) 232 233 234 def _ISIS_GuessTlvClass_Helper(tlv_classes, defaultname, p, **kargs): 235 cls = conf.raw_layer 236 if len(p) >= 2: 237 tlvtype = orb(p[0]) 238 clsname = tlv_classes.get(tlvtype, defaultname) 239 cls = globals()[clsname] 240 241 return cls(p, **kargs) 242 243 244 class _ISIS_GenericTlv_Base(Packet): 245 fields_desc = [ByteField("type", 0), 246 FieldLenField("len", None, length_of="val", fmt="B"), 247 BoundStrLenField("val", "", length_from=lambda pkt: pkt.len)] 248 249 def guess_payload_class(self, p): 250 return conf.padding_layer 251 252 253 class ISIS_GenericTlv(_ISIS_GenericTlv_Base): 254 name = "ISIS Generic TLV" 255 256 257 class ISIS_GenericSubTlv(_ISIS_GenericTlv_Base): 258 name = "ISIS Generic Sub-TLV" 259 260 261 ####################################################################### 262 ## ISIS Sub-TLVs for TLVs 22, 23, 141, 222, 223 ## 263 ####################################################################### 264 _isis_subtlv_classes_1 = { 265 4: "ISIS_LinkLocalRemoteIdentifiersSubTlv", 266 6: "ISIS_IPv4InterfaceAddressSubTlv", 267 8: "ISIS_IPv4NeighborAddressSubTlv", 268 12: "ISIS_IPv6InterfaceAddressSubTlv", 269 13: "ISIS_IPv6NeighborAddressSubTlv" 270 } 271 272 _isis_subtlv_names_1 = { 273 4: "Link Local/Remote Identifiers", 274 6: "IPv4 Interface Address", 275 8: "IPv4 Neighbor Address", 276 12: "IPv6 Interface Address", 277 13: "IPv6 Neighbor Address" 278 } 279 280 281 def _ISIS_GuessSubTlvClass_1(p, **kargs): 282 return _ISIS_GuessTlvClass_Helper(_isis_subtlv_classes_1, "ISIS_GenericSubTlv", p, **kargs) 283 284 285 class ISIS_IPv4InterfaceAddressSubTlv(ISIS_GenericSubTlv): 286 name = "ISIS IPv4 Interface Address (S)" 287 fields_desc = [ByteEnumField("type", 6, _isis_subtlv_names_1), 288 FieldLenField("len", None, length_of= "address", fmt="B"), 289 IPField("address", "0.0.0.0")] 290 291 292 class ISIS_IPv4NeighborAddressSubTlv(ISIS_GenericSubTlv): 293 name = "ISIS IPv4 Neighbor Address (S)" 294 fields_desc = [ByteEnumField("type", 8, _isis_subtlv_names_1), 295 FieldLenField("len", None, length_of= "address", fmt="B"), 296 IPField("address", "0.0.0.0")] 297 298 299 class ISIS_LinkLocalRemoteIdentifiersSubTlv(ISIS_GenericSubTlv): 300 name = "ISIS Link Local/Remote Identifiers (S)" 301 fields_desc = [ByteEnumField("type", 4, _isis_subtlv_names_1), 302 FieldLenField("len", 8, fmt="B"), 303 IntField("localid", "0"), 304 IntField("remoteid", "0")] 305 306 307 class ISIS_IPv6InterfaceAddressSubTlv(ISIS_GenericSubTlv): 308 name = "ISIS IPv6 Interface Address (S)" 309 fields_desc = [ByteEnumField("type", 12, _isis_subtlv_names_1), 310 FieldLenField("len", None, length_of= "address", fmt="B"), 311 IP6Field("address", "::")] 312 313 314 class ISIS_IPv6NeighborAddressSubTlv(ISIS_GenericSubTlv): 315 name = "ISIS IPv6 Neighbor Address (S)" 316 fields_desc = [ByteEnumField("type", 13, _isis_subtlv_names_1), 317 FieldLenField("len", None, length_of= "address", fmt="B"), 318 IP6Field("address", "::")] 319 320 321 ####################################################################### 322 ## ISIS Sub-TLVs for TLVs 135, 235, 236, and 237 ## 323 ####################################################################### 324 _isis_subtlv_classes_2 = { 325 1: "ISIS_32bitAdministrativeTagSubTlv", 326 2: "ISIS_64bitAdministrativeTagSubTlv" 327 } 328 329 _isis_subtlv_names_2 = { 330 1: "32-bit Administrative Tag", 331 2: "64-bit Administrative Tag" 332 } 333 334 335 def _ISIS_GuessSubTlvClass_2(p, **kargs): 336 return _ISIS_GuessTlvClass_Helper(_isis_subtlv_classes_2, "ISIS_GenericSubTlv", p, **kargs) 337 338 339 class ISIS_32bitAdministrativeTagSubTlv(ISIS_GenericSubTlv): 340 name = "ISIS 32-bit Administrative Tag (S)" 341 fields_desc = [ByteEnumField("type", 1, _isis_subtlv_names_2), 342 FieldLenField("len", None, length_of= "tags", fmt="B"), 343 FieldListField("tags", [], IntField("", 0), count_from= lambda pkt: pkt.len // 4)] 344 345 346 class ISIS_64bitAdministrativeTagSubTlv(ISIS_GenericSubTlv): 347 name = "ISIS 64-bit Administrative Tag (S)" 348 fields_desc = [ByteEnumField("type", 2, _isis_subtlv_names_2), 349 FieldLenField("len", None, length_of= "tags", fmt="B"), 350 FieldListField("tags", [], LongField("", 0), count_from= lambda pkt: pkt.len // 8)] 351 352 353 ####################################################################### 354 ## ISIS TLVs ## 355 ####################################################################### 356 _isis_tlv_classes = { 357 1: "ISIS_AreaTlv", 358 2: "ISIS_IsReachabilityTlv", 359 6: "ISIS_IsNeighbourTlv", 360 8: "ISIS_PaddingTlv", 361 9: "ISIS_LspEntryTlv", 362 10: "ISIS_AuthenticationTlv", 363 12: "ISIS_ChecksumTlv", 364 14: "ISIS_BufferSizeTlv", 365 22: "ISIS_ExtendedIsReachabilityTlv", 366 128: "ISIS_InternalIpReachabilityTlv", 367 129: "ISIS_ProtocolsSupportedTlv", 368 130: "ISIS_ExternalIpReachabilityTlv", 369 132: "ISIS_IpInterfaceAddressTlv", 370 135: "ISIS_ExtendedIpReachabilityTlv", 371 137: "ISIS_DynamicHostnameTlv", 372 232: "ISIS_Ipv6InterfaceAddressTlv", 373 236: "ISIS_Ipv6ReachabilityTlv", 374 240: "ISIS_P2PAdjacencyStateTlv" 375 } 376 377 _isis_tlv_names = { 378 1: "Area TLV", 379 2: "IS Reachability TLV", 380 6: "IS Neighbour TLV", 381 7: "Instance Identifier TLV", 382 8: "Padding TLV", 383 9: "LSP Entries TLV", 384 10: "Authentication TLV", 385 12: "Optional Checksum TLV", 386 13: "Purge Originator Identification TLV", 387 14: "LSP Buffer Size TLV", 388 22: "Extended IS-Reachability TLV", 389 23: "IS Neighbour Attribute TLV", 390 24: "IS Alias ID", 391 128: "IP Internal Reachability TLV", 392 129: "Protocols Supported TLV", 393 130: "IP External Reachability TLV", 394 131: "Inter-Domain Routing Protocol Information TLV", 395 132: "IP Interface Address TLV", 396 134: "Traffic Engineering Router ID TLV", 397 135: "Extended IP Reachability TLV", 398 137: "Dynamic Hostname TLV", 399 138: "GMPLS Shared Risk Link Group TLV", 400 139: "IPv6 Shared Risk Link Group TLV", 401 140: "IPv6 Traffic Engineering Router ID TLV", 402 141: "Inter-AS Reachability Information TLV", 403 142: "Group Address TLV", 404 143: "Multi-Topology-Aware Port Capability TLV", 405 144: "Multi-Topology Capability TLV", 406 145: "TRILL Neighbour TLV", 407 147: "MAC-Reachability TLV", 408 148: "BFD-Enabled TLV", 409 211: "Restart TLV", 410 222: "Multi-Topology Intermediate Systems TLV", 411 223: "Multi-Topology IS Neighbour Attributes TLV", 412 229: "Multi-Topology TLV", 413 232: "IPv6 Interface Address TLV", 414 233: "IPv6 Global Interface Address TLV", 415 235: "Multi-Topology IPv4 Reachability TLV", 416 236: "IPv6 Reachability TLV", 417 237: "Multi-Topology IPv6 Reachability TLV", 418 240: "Point-to-Point Three-Way Adjacency TLV", 419 242: "IS-IS Router Capability TLV", 420 251: "Generic Information TLV" 421 } 422 423 424 def _ISIS_GuessTlvClass(p, **kargs): 425 return _ISIS_GuessTlvClass_Helper(_isis_tlv_classes, "ISIS_GenericTlv", p, **kargs) 426 427 428 class ISIS_AreaEntry(Packet): 429 name = "ISIS Area Entry" 430 fields_desc = [FieldLenField("arealen", None, length_of="areaid", fmt="B"), 431 ISIS_AreaIdField("areaid", "49", length_from=lambda pkt: pkt.arealen)] 432 433 def extract_padding(self, s): 434 return "", s 435 436 437 class ISIS_AreaTlv(ISIS_GenericTlv): 438 name = "ISIS Area TLV" 439 fields_desc = [ByteEnumField("type", 1, _isis_tlv_names), 440 FieldLenField("len", None, length_of= "areas", fmt="B"), 441 PacketListField("areas", [], ISIS_AreaEntry, length_from=lambda x: x.len)] 442 443 444 class ISIS_AuthenticationTlv(ISIS_GenericTlv): 445 name = "ISIS Authentication TLV" 446 fields_desc = [ByteEnumField("type", 10, _isis_tlv_names), 447 FieldLenField("len", None, length_of= "password", adjust=lambda pkt,x: x + 1, fmt="B"), 448 ByteEnumField("authtype", 1, {1: "Plain", 17: "HMAC-MD5"}), 449 BoundStrLenField("password", "", maxlen= 254, length_from=lambda pkt: pkt.len - 1)] 450 451 452 class ISIS_BufferSizeTlv(ISIS_GenericTlv): 453 name = "ISIS Buffer Size TLV" 454 fields_desc = [ByteEnumField("type", 14, _isis_tlv_names), 455 ByteField("len", 2), 456 ShortField("lspbuffersize", 1497)] 457 458 459 class ISIS_ChecksumTlv(ISIS_GenericTlv): 460 name = "ISIS Optional Checksum TLV" 461 fields_desc = [ByteEnumField("type", 12, _isis_tlv_names), 462 ByteField("len", 2), 463 XShortField("checksum", None)] 464 465 466 class ISIS_DynamicHostnameTlv(ISIS_GenericTlv): 467 name = "ISIS Dynamic Hostname TLV" 468 fields_desc = [ByteEnumField("type", 137, _isis_tlv_names), 469 FieldLenField("len", None, length_of= "hostname", fmt="B"), 470 BoundStrLenField("hostname", "", length_from=lambda pkt: pkt.len)] 471 472 473 class ISIS_ExtendedIpPrefix(Packet): 474 name = "ISIS Extended IP Prefix" 475 fields_desc = [ 476 IntField("metric", 1), 477 BitField("updown", 0, 1), 478 BitField("subtlvindicator", 0, 1), 479 BitFieldLenField("pfxlen", None, 6, length_of="pfx"), 480 IPPrefixField("pfx", None, wordbytes=1, length_from=lambda x: x.pfxlen), 481 ConditionalField(FieldLenField("subtlvslen", None, length_of="subtlvs", fmt= "B"), lambda pkt: pkt.subtlvindicator == 1), 482 ConditionalField(PacketListField("subtlvs", [], _ISIS_GuessSubTlvClass_2, length_from=lambda x: x.subtlvslen), lambda pkt: pkt.subtlvindicator == 1) 483 ] 484 485 def extract_padding(self, s): 486 return "", s 487 488 489 class ISIS_ExtendedIpReachabilityTlv(ISIS_GenericTlv): 490 name = "ISIS Extended IP Reachability TLV" 491 fields_desc = [ByteEnumField("type", 135, _isis_tlv_names), 492 FieldLenField("len", None, length_of="pfxs", fmt="B"), 493 PacketListField("pfxs", [], ISIS_ExtendedIpPrefix, length_from= lambda pkt: pkt.len)] 494 495 496 class ISIS_ExtendedIsNeighbourEntry(Packet): 497 name = "ISIS Extended IS Neighbour Entry" 498 fields_desc = [ 499 ISIS_NodeIdField("neighbourid", "0102.0304.0506.07"), 500 ThreeBytesField("metric", 1), 501 FieldLenField("subtlvslen", None, length_of="subtlvs", fmt= "B"), 502 PacketListField("subtlvs", [], _ISIS_GuessSubTlvClass_1, length_from=lambda x: x.subtlvslen) 503 ] 504 505 def extract_padding(self, s): 506 return "", s 507 508 509 class ISIS_ExtendedIsReachabilityTlv(ISIS_GenericTlv): 510 name = "ISIS Extended IS Reachability TLV" 511 fields_desc = [ByteEnumField("type", 22, _isis_tlv_names), 512 FieldLenField("len", None, length_of="neighbours", fmt="B"), 513 PacketListField("neighbours", [], ISIS_ExtendedIsNeighbourEntry, length_from=lambda x: x.len)] 514 515 516 class ISIS_IpInterfaceAddressTlv(ISIS_GenericTlv): 517 name = "ISIS IP Interface Address TLV" 518 fields_desc = [ByteEnumField("type", 132, _isis_tlv_names), 519 FieldLenField("len", None, length_of= "addresses", fmt="B"), 520 FieldListField("addresses", [], IPField("", "0.0.0.0"), count_from= lambda pkt: pkt.len // 4)] 521 522 523 class ISIS_Ipv6InterfaceAddressTlv(ISIS_GenericTlv): 524 name = "ISIS IPv6 Interface Address TLV" 525 fields_desc = [ 526 ByteEnumField("type", 232, _isis_tlv_names), 527 FieldLenField("len", None, length_of="addresses", fmt="B"), 528 IP6ListField("addresses", [], count_from=lambda pkt: pkt.len // 16) 529 ] 530 531 532 class ISIS_Ipv6Prefix(Packet): 533 name = "ISIS IPv6 Prefix" 534 fields_desc = [ 535 IntField("metric", 1), 536 BitField("updown", 0, 1), 537 BitField("external", 0, 1), 538 BitField("subtlvindicator", 0, 1), 539 BitField("reserved", 0, 5), 540 FieldLenField("pfxlen", None, length_of="pfx", fmt="B"), 541 IP6PrefixField("pfx", None, wordbytes=1, length_from=lambda x: x.pfxlen), 542 ConditionalField(FieldLenField("subtlvslen", None, length_of="subtlvs", fmt= "B"), lambda pkt: pkt.subtlvindicator == 1), 543 ConditionalField(PacketListField("subtlvs", [], _ISIS_GuessSubTlvClass_2, length_from=lambda x: x.subtlvslen), lambda pkt: pkt.subtlvindicator == 1) 544 ] 545 546 def extract_padding(self, s): 547 return "", s 548 549 550 class ISIS_Ipv6ReachabilityTlv(ISIS_GenericTlv): 551 name= "ISIS IPv6 Reachability TLV" 552 fields_desc = [ByteEnumField("type", 236, _isis_tlv_names), 553 FieldLenField("len", None, length_of= "pfxs", fmt="B"), 554 PacketListField("pfxs", [], ISIS_Ipv6Prefix, length_from= lambda pkt: pkt.len)] 555 556 557 class ISIS_IsNeighbourTlv(ISIS_GenericTlv): 558 name = "ISIS IS Neighbour TLV" 559 fields_desc = [ByteEnumField("type", 6, _isis_tlv_names), 560 FieldLenField("len", None, length_of= "neighbours", fmt="B"), 561 FieldListField("neighbours", [], MACField("", "00.00.00.00.00.00"), count_from= lambda pkt: pkt.len // 6)] 562 563 564 class ISIS_LspEntry(Packet): 565 name = "ISIS LSP Entry" 566 fields_desc = [ShortField("lifetime", 1200), 567 ISIS_LspIdField("lspid", "0102.0304.0506.07-08"), 568 XIntField("seqnum", 0x00000001), 569 XShortField("checksum", None)] 570 571 def extract_padding(self, s): 572 return "", s 573 574 575 class ISIS_LspEntryTlv(ISIS_GenericTlv): 576 name = "ISIS LSP Entry TLV" 577 fields_desc = [ 578 ByteEnumField("type", 9, _isis_tlv_names), 579 FieldLenField("len", None, length_of="entries", fmt="B"), 580 PacketListField("entries", [], ISIS_LspEntry, count_from=lambda pkt: pkt.len // 16) 581 ] 582 583 584 class _AdjacencyStateTlvLenField(Field): 585 def i2m(self, pkt, x): 586 if pkt.neighbourextlocalcircuitid is not None: 587 return 15 588 589 if pkt.neighboursystemid is not None: 590 return 11 591 592 if pkt.extlocalcircuitid is not None: 593 return 5 594 595 return 1 596 597 598 class ISIS_P2PAdjacencyStateTlv(ISIS_GenericTlv): 599 name = "ISIS P2P Adjacency State TLV" 600 fields_desc = [ByteEnumField("type", 240, _isis_tlv_names), 601 _AdjacencyStateTlvLenField("len", None, fmt="B"), 602 ByteEnumField("state", "Down", {0x2 : "Down", 0x1 : "Initialising", 0x0 : "Up"}), 603 ConditionalField(IntField("extlocalcircuitid", None), lambda pkt: pkt.len >= 5), 604 ConditionalField(ISIS_SystemIdField("neighboursystemid", None), lambda pkt: pkt.len >= 11), 605 ConditionalField(IntField("neighbourextlocalcircuitid", None), lambda pkt: pkt.len == 15)] 606 607 608 # TODO dynamically allocate sufficient size 609 class ISIS_PaddingTlv(ISIS_GenericTlv): 610 name = "ISIS Padding TLV" 611 fields_desc = [ 612 ByteEnumField("type", 8, _isis_tlv_names), 613 FieldLenField("len", None, length_of="padding", fmt="B"), 614 BoundStrLenField("padding", "", length_from=lambda pkt: pkt.len) 615 ] 616 617 618 class ISIS_ProtocolsSupportedTlv(ISIS_GenericTlv): 619 name = "ISIS Protocols Supported TLV" 620 fields_desc = [ 621 ByteEnumField("type", 129, _isis_tlv_names), 622 FieldLenField("len", None, count_of="nlpids", fmt="B"), 623 FieldListField("nlpids", [], ByteEnumField("", "IPv4", network_layer_protocol_ids), count_from=lambda pkt: pkt.len) 624 ] 625 626 627 ####################################################################### 628 ## ISIS Old-Style TLVs ## 629 ####################################################################### 630 631 class ISIS_IpReachabilityEntry(Packet): 632 name = "ISIS IP Reachability" 633 fields_desc = [ByteField("defmetric", 1), 634 ByteField("delmetric", 0x80), 635 ByteField("expmetric", 0x80), 636 ByteField("errmetric", 0x80), 637 IPField("ipaddress", "0.0.0.0"), 638 IPField("subnetmask", "255.255.255.255")] 639 640 def extract_padding(self, s): 641 return "", s 642 643 644 class ISIS_InternalIpReachabilityTlv(ISIS_GenericTlv): 645 name = "ISIS Internal IP Reachability TLV" 646 fields_desc = [ 647 ByteEnumField("type", 128, _isis_tlv_names), 648 FieldLenField("len", None, length_of="entries", fmt="B"), 649 PacketListField("entries", [], ISIS_IpReachabilityEntry, count_from=lambda x: x.len // 12) 650 ] 651 652 653 class ISIS_ExternalIpReachabilityTLV(ISIS_GenericTlv): 654 name = "ISIS External IP Reachability TLV" 655 fields_desc = [ 656 ByteEnumField("type", 130, _isis_tlv_names), 657 FieldLenField("len", None, length_of="entries", fmt="B"), 658 PacketListField("entries", [], ISIS_IpReachabilityEntry, count_from=lambda x: x.len // 12) 659 ] 660 661 662 class ISIS_IsReachabilityEntry(Packet): 663 name = "ISIS IS Reachability" 664 fields_desc = [ByteField("defmetric", 1), 665 ByteField("delmetric", 0x80), 666 ByteField("expmetric", 0x80), 667 ByteField("errmetric", 0x80), 668 ISIS_NodeIdField("neighbourid", "0102.0304.0506.07")] 669 670 def extract_padding(self, s): 671 return "", s 672 673 674 class ISIS_IsReachabilityTlv(ISIS_GenericTlv): 675 name = "ISIS IS Reachability TLV" 676 fields_desc = [ 677 ByteEnumField("type", 2, _isis_tlv_names), 678 FieldLenField("len", None, fmt="B", length_of="neighbours", adjust=lambda pkt,x: x+1), 679 ByteField("virtual", 0), 680 PacketListField("neighbours", [], ISIS_IsReachabilityEntry, count_from=lambda x: (x.len - 1) // 11) 681 ] 682 683 ####################################################################### 684 ## ISIS PDU Packets ## 685 ####################################################################### 686 _isis_pdu_names = { 687 15: "L1 LAN Hello", 688 16: "L2 LAN Hello", 689 17: "P2P Hello", 690 18: "L1 LSP", 691 20: "L2 LSP", 692 24: "L1 CSNP", 693 25: "L2 CSNP", 694 26: "L1 PSNP", 695 27: "L2 PSNP" 696 } 697 698 699 class ISIS_CommonHdr(Packet): 700 name = "ISIS Common Header" 701 fields_desc = [ 702 ByteEnumField("nlpid", 0x83, network_layer_protocol_ids), 703 ByteField("hdrlen", None), 704 ByteField("version", 1), 705 ByteField("idlen", 0), 706 ByteEnumField("pdutype", None, _isis_pdu_names), 707 ByteField("pduversion", 1), 708 ByteField("hdrreserved", 0), 709 ByteField("maxareaaddr", 0) 710 ] 711 712 def post_build(self, pkt, pay): 713 # calculating checksum if requested 714 pdu = pkt + pay 715 checksumInfo = self[1].checksum_info(self.hdrlen) 716 717 if checksumInfo is not None: 718 (cbegin, cpos) = checksumInfo 719 checkbytes = fletcher16_checkbytes(pdu[cbegin:], (cpos - cbegin)) 720 pdu = pdu[:cpos] + checkbytes + pdu[cpos+2:] 721 722 return pdu 723 724 725 class _ISIS_PduBase(Packet): 726 def checksum_info(self, hdrlen): 727 checksumPosition = hdrlen 728 for tlv in self.tlvs: 729 if isinstance(tlv, ISIS_ChecksumTlv): 730 checksumPosition += 2 731 return (0, checksumPosition) 732 else: 733 checksumPosition += len(tlv) 734 735 return None 736 737 def guess_payload_class(self, p): 738 return conf.padding_layer 739 740 741 class _ISIS_PduLengthField(FieldLenField): 742 def __init__(self): 743 FieldLenField.__init__(self, "pdulength", None, length_of="tlvs", adjust=lambda pkt,x: x + pkt.underlayer.hdrlen) 744 745 746 class _ISIS_TlvListField(PacketListField): 747 def __init__(self): 748 PacketListField.__init__(self, "tlvs", [], _ISIS_GuessTlvClass, length_from= lambda pkt: pkt.pdulength - pkt.underlayer.hdrlen) 749 750 751 class _ISIS_LAN_HelloBase(_ISIS_PduBase): 752 fields_desc = [ 753 ISIS_CircuitTypeField(), 754 ISIS_SystemIdField("sourceid", "0102.0304.0506"), 755 ShortField("holdingtime", 30), 756 _ISIS_PduLengthField(), 757 ByteField("priority", 1), 758 ISIS_NodeIdField("lanid", "0000.0000.0000.00"), 759 _ISIS_TlvListField() 760 ] 761 762 763 class ISIS_L1_LAN_Hello(_ISIS_LAN_HelloBase): 764 name = "ISIS L1 LAN Hello PDU" 765 766 767 class ISIS_L2_LAN_Hello(_ISIS_LAN_HelloBase): 768 name = "ISIS L2 LAN Hello PDU" 769 770 771 class ISIS_P2P_Hello(_ISIS_PduBase): 772 name = "ISIS Point-to-Point Hello PDU" 773 774 fields_desc = [ 775 ISIS_CircuitTypeField(), 776 ISIS_SystemIdField("sourceid", "0102.0304.0506"), 777 ShortField("holdingtime", 30), 778 _ISIS_PduLengthField(), 779 ByteField("localcircuitid", 0), 780 _ISIS_TlvListField() 781 ] 782 783 784 class _ISIS_LSP_Base(_ISIS_PduBase): 785 fields_desc = [ 786 _ISIS_PduLengthField(), 787 ShortField("lifetime", 1199), 788 ISIS_LspIdField("lspid", "0102.0304.0506.00-00"), 789 XIntField("seqnum", 0x00000001), 790 XShortField("checksum", None), 791 FlagsField("typeblock", 0x03, 8, ["L1", "L2", "OL", "ADef", "ADel", "AExp", "AErr", "P"]), 792 _ISIS_TlvListField() 793 ] 794 795 def checksum_info(self, hdrlen): 796 if self.checksum is not None: 797 return None 798 799 return (12, 24) 800 801 802 def _lsp_answers(lsp, other, clsname): 803 # TODO 804 return 0 805 806 807 class ISIS_L1_LSP(_ISIS_LSP_Base): 808 name = "ISIS L1 Link State PDU" 809 810 def answers(self, other): 811 return _lsp_answers(self, other, "ISIS_L1_PSNP") 812 813 814 class ISIS_L2_LSP(_ISIS_LSP_Base): 815 name = "ISIS L2 Link State PDU" 816 817 def answers(self, other): 818 return _lsp_answers(self, other, "ISIS_L2_PSNP") 819 820 821 class _ISIS_CSNP_Base(_ISIS_PduBase): 822 fields_desc = [ 823 _ISIS_PduLengthField(), 824 ISIS_NodeIdField("sourceid", "0102.0304.0506.00"), 825 ISIS_LspIdField("startlspid", "0000.0000.0000.00-00"), 826 ISIS_LspIdField("endlspid", "FFFF.FFFF.FFFF.FF-FF"), 827 _ISIS_TlvListField() 828 ] 829 830 831 def _snp_answers(snp, other, clsname): 832 # TODO 833 return 0 834 835 836 class ISIS_L1_CSNP(_ISIS_CSNP_Base): 837 name = "ISIS L1 Complete Sequence Number Packet" 838 839 def answers(self, other): 840 return _snp_answers(self, other, "ISIS_L1_LSP") 841 842 843 class ISIS_L2_CSNP(_ISIS_CSNP_Base): 844 name = "ISIS L2 Complete Sequence Number Packet" 845 846 def answers(self, other): 847 return _snp_answers(self, other, "ISIS_L2_LSP") 848 849 850 class _ISIS_PSNP_Base(_ISIS_PduBase): 851 fields_desc = [ 852 _ISIS_PduLengthField(), 853 ISIS_NodeIdField("sourceid", "0102.0304.0506.00"), 854 _ISIS_TlvListField() 855 ] 856 857 858 class ISIS_L1_PSNP(_ISIS_PSNP_Base): 859 name = "ISIS L1 Partial Sequence Number Packet" 860 861 def answers(self, other): 862 return _snp_answers(self, other, "ISIS_L1_LSP") 863 864 865 class ISIS_L2_PSNP(_ISIS_PSNP_Base): 866 name = "ISIS L2 Partial Sequence Number Packet" 867 868 def answers(self, other): 869 return _snp_answers(self, other, "ISIS_L2_LSP") 870 871 register_cln_protocol(0x83, ISIS_CommonHdr) 872 bind_layers(ISIS_CommonHdr, ISIS_L1_LAN_Hello, hdrlen=27, pdutype=15) 873 bind_layers(ISIS_CommonHdr, ISIS_L2_LAN_Hello, hdrlen=27, pdutype=16) 874 bind_layers(ISIS_CommonHdr, ISIS_P2P_Hello, hdrlen=20, pdutype=17) 875 bind_layers(ISIS_CommonHdr, ISIS_L1_LSP, hdrlen=27, pdutype=18) 876 bind_layers(ISIS_CommonHdr, ISIS_L2_LSP, hdrlen=27, pdutype=20) 877 bind_layers(ISIS_CommonHdr, ISIS_L1_CSNP, hdrlen=33, pdutype=24) 878 bind_layers(ISIS_CommonHdr, ISIS_L2_CSNP, hdrlen=33, pdutype=25) 879 bind_layers(ISIS_CommonHdr, ISIS_L1_PSNP, hdrlen=17, pdutype=26) 880 bind_layers(ISIS_CommonHdr, ISIS_L2_PSNP, hdrlen=17, pdutype=27) 881 882