1# SPDX-License-Identifier: GPL-2.0-or-later 2# This file is part of Scapy 3# See https://scapy.net/ for more information 4 5# scapy.contrib.description = BGP v0.1 6# scapy.contrib.status = loads 7 8""" 9BGP (Border Gateway Protocol). 10""" 11 12import struct 13import re 14import socket 15 16from scapy import pton_ntop 17from scapy.packet import Packet, Packet_metaclass, bind_layers 18from scapy.fields import (Field, BitField, BitEnumField, XBitField, ByteField, 19 ByteEnumField, ShortField, ShortEnumField, IntField, 20 IntEnumField, LongField, IEEEFloatField, StrField, 21 StrLenField, StrFixedLenField, FieldLenField, 22 FieldListField, PacketField, PacketListField, 23 IPField, FlagsField, ConditionalField, 24 MultiEnumField) 25from scapy.layers.inet import TCP 26from scapy.layers.inet6 import IP6Field 27from scapy.config import conf, ConfClass 28from scapy.compat import orb, chb 29from scapy.error import log_runtime 30 31 32# 33# Module configuration 34# 35 36 37class BGPConf(ConfClass): 38 """ 39 BGP module configuration. 40 """ 41 42 # By default, set to True in order to behave like an OLD speaker (RFC 6793) 43 use_2_bytes_asn = True 44 45 46bgp_module_conf = BGPConf() 47 48 49# 50# Constants 51# 52 53# RFC 4271: "The maximum message size is 4096 octets. All implementations are 54# required to support this maximum message size." 55BGP_MAXIMUM_MESSAGE_SIZE = 4096 56 57# RFC 4271: "Each message has a fixed-size header." Marker (16 bytes) + 58# Length (2 bytes) + Type (1 byte) 59_BGP_HEADER_SIZE = 19 60 61# Marker included in every message (RFC 4271: "This 16-octet field is 62# included for compatibility; it MUST be set to all ones") 63_BGP_HEADER_MARKER = b"\xff" * 16 64 65# extended-length flag (RFC 4271 4.3. UPDATE Message Format - 66# Path Attributes) 67_BGP_PA_EXTENDED_LENGTH = 0x10 68 69# RFC 5492 (at least 2 bytes : code + length) 70_BGP_CAPABILITY_MIN_SIZE = 2 71 72# RFC 5492 (at least 3 bytes : type code + length) 73_BGP_PATH_ATTRIBUTE_MIN_SIZE = 3 74 75 76# 77# Fields and utilities 78# 79 80def _bits_to_bytes_len(length_in_bits): 81 """ 82 Helper function that returns the numbers of bytes necessary to store the 83 given number of bits. 84 """ 85 86 return (length_in_bits + 7) // 8 87 88 89class BGPFieldIPv4(Field): 90 """ 91 IPv4 Field (CIDR) 92 """ 93 94 def mask2iplen(self, mask): 95 """Get the IP field mask length (in bytes).""" 96 return (mask + 7) // 8 97 98 def h2i(self, pkt, h): 99 """x.x.x.x/y to "internal" representation.""" 100 ip, mask = re.split("/", h) 101 return int(mask), ip 102 103 def i2h(self, pkt, i): 104 """"Internal" representation to "human" representation 105 (x.x.x.x/y).""" 106 mask, ip = i 107 return ip + "/" + str(mask) 108 109 def i2repr(self, pkt, i): 110 return self.i2h(pkt, i) 111 112 def i2len(self, pkt, i): 113 mask, _ = i 114 return self.mask2iplen(mask) + 1 115 116 def i2m(self, pkt, i): 117 """"Internal" (IP as bytes, mask as int) to "machine" 118 representation.""" 119 mask, ip = i 120 ip = socket.inet_aton(ip) 121 return struct.pack(">B", mask) + ip[:self.mask2iplen(mask)] 122 123 def addfield(self, pkt, s, val): 124 return s + self.i2m(pkt, val) 125 126 def getfield(self, pkt, s): 127 length = self.mask2iplen(orb(s[0])) + 1 128 return s[length:], self.m2i(pkt, s[:length]) 129 130 def m2i(self, pkt, m): 131 mask = orb(m[0]) 132 mask2iplen_res = self.mask2iplen(mask) 133 ip = b"".join(m[i + 1:i + 2] if i < mask2iplen_res else b"\x00" for i in range(4)) # noqa: E501 134 return (mask, socket.inet_ntoa(ip)) 135 136 137class BGPFieldIPv6(Field): 138 """IPv6 Field (CIDR)""" 139 140 def mask2iplen(self, mask): 141 """Get the IP field mask length (in bytes).""" 142 return (mask + 7) // 8 143 144 def h2i(self, pkt, h): 145 """x.x.x.x/y to internal representation.""" 146 ip, mask = re.split("/", h) 147 return int(mask), ip 148 149 def i2h(self, pkt, i): 150 """"Internal" representation to "human" representation.""" 151 mask, ip = i 152 return ip + "/" + str(mask) 153 154 def i2repr(self, pkt, i): 155 return self.i2h(pkt, i) 156 157 def i2len(self, pkt, i): 158 mask, ip = i 159 return self.mask2iplen(mask) + 1 160 161 def i2m(self, pkt, i): 162 """"Internal" (IP as bytes, mask as int) to "machine" representation.""" # noqa: E501 163 mask, ip = i 164 ip = pton_ntop.inet_pton(socket.AF_INET6, ip) 165 return struct.pack(">B", mask) + ip[:self.mask2iplen(mask)] 166 167 def addfield(self, pkt, s, val): 168 return s + self.i2m(pkt, val) 169 170 def getfield(self, pkt, s): 171 length = self.mask2iplen(orb(s[0])) + 1 172 return s[length:], self.m2i(pkt, s[:length]) 173 174 def m2i(self, pkt, m): 175 mask = orb(m[0]) 176 ip = b"".join(m[i + 1:i + 2] if i < self.mask2iplen(mask) else b"\x00" for i in range(16)) # noqa: E501 177 return (mask, pton_ntop.inet_ntop(socket.AF_INET6, ip)) 178 179 180def has_extended_length(flags): 181 """ 182 Used in BGPPathAttr to check if the extended-length flag is 183 set. 184 """ 185 186 return flags & _BGP_PA_EXTENDED_LENGTH == _BGP_PA_EXTENDED_LENGTH 187 188 189def detect_add_path_prefix46(s, max_bit_length): 190 """ 191 Detect IPv4/IPv6 prefixes conform to BGP Additional Path but NOT conform 192 to standard BGP.. 193 194 This is an adapted version of wireshark's detect_add_path_prefix46 195 https://github.com/wireshark/wireshark/blob/ed9e958a2ed506220fdab320738f1f96a3c2ffbb/epan/dissectors/packet-bgp.c#L2905 196 Kudos to them ! 197 """ 198 # Must be compatible with BGP Additional Path 199 i = 0 200 while i + 4 < len(s): 201 i += 4 202 prefix_len = orb(s[i]) 203 if prefix_len > max_bit_length: 204 return False 205 addr_len = (prefix_len + 7) // 8 206 i += 1 + addr_len 207 if i > len(s): 208 return False 209 if prefix_len % 8: 210 if orb(s[i - 1]) & (0xFF >> (prefix_len % 8)): 211 return False 212 # Must NOT be compatible with standard BGP 213 i = 0 214 while i + 4 < len(s): 215 prefix_len = orb(s[i]) 216 if prefix_len == 0 and len(s) > 1: 217 return True 218 if prefix_len > max_bit_length: 219 return True 220 addr_len = (prefix_len + 7) // 8 221 i += 1 + addr_len 222 if i > len(s): 223 return True 224 if prefix_len % 8: 225 if orb(s[i - 1]) & (0xFF >> (prefix_len % 8)): 226 return True 227 return False 228 229 230class BGPNLRI_IPv4(Packet): 231 """ 232 Packet handling IPv4 NLRI fields. 233 """ 234 name = "IPv4 NLRI" 235 fields_desc = [BGPFieldIPv4("prefix", "0.0.0.0/0")] 236 237 def default_payload_class(self, payload): 238 return conf.padding_layer 239 240 241class BGPNLRI_IPv6(Packet): 242 """ 243 Packet handling IPv6 NLRI fields. 244 """ 245 name = "IPv6 NLRI" 246 fields_desc = [BGPFieldIPv6("prefix", "::/0")] 247 248 def default_payload_class(self, payload): 249 return conf.padding_layer 250 251 252class BGPNLRI_IPv4_AP(BGPNLRI_IPv4): 253 """ 254 Packet handling IPv4 NLRI fields WITH BGP ADDITIONAL PATH 255 """ 256 257 name = "IPv4 NLRI (Additional Path)" 258 fields_desc = [IntField("nlri_path_id", 0), 259 BGPFieldIPv4("prefix", "0.0.0.0/0")] 260 261 262class BGPNLRI_IPv6_AP(BGPNLRI_IPv6): 263 """ 264 Packet handling IPv6 NLRI fields WITH BGP ADDITIONAL PATH 265 """ 266 267 name = "IPv6 NLRI (Additional Path)" 268 fields_desc = [IntField("nlri_path_id", 0), 269 BGPFieldIPv6("prefix", "::/0")] 270 271 272class BGPNLRIPacketListField(PacketListField): 273 """ 274 PacketListField handling NLRI fields. 275 """ 276 __slots__ = ["max_bit_length", "cls_group", "no_length"] 277 278 def __init__(self, name, default, ip_mode, **kwargs): 279 super(BGPNLRIPacketListField, self).__init__( 280 name, default, Packet, **kwargs 281 ) 282 self.max_bit_length, self.cls_group = { 283 "IPv4": (32, [BGPNLRI_IPv4, BGPNLRI_IPv4_AP]), 284 "IPv6": (128, [BGPNLRI_IPv6, BGPNLRI_IPv6_AP]), 285 }[ip_mode] 286 self.no_length = "length_from" not in kwargs 287 288 def getfield(self, pkt, s): 289 if self.no_length: 290 index = s.find(_BGP_HEADER_MARKER) 291 if index == 0: 292 return s, [] 293 if index != -1: 294 self.length_from = lambda pkt: index 295 remain = s[:self.length_from(pkt)] if self.length_from else s 296 297 cls = self.cls_group[ 298 detect_add_path_prefix46(remain, self.max_bit_length) 299 ] 300 self.next_cls_cb = lambda *args: cls 301 res = super(BGPNLRIPacketListField, self).getfield(pkt, s) 302 if self.no_length: 303 self.length_from = None 304 return res 305 306 307class _BGPInvalidDataException(Exception): 308 """ 309 Raised when it is not possible to instantiate a BGP packet with the given 310 data. 311 """ 312 313 def __init__(self, details): 314 Exception.__init__( 315 self, 316 "Impossible to build packet from the given data" + details 317 ) 318 319 320def _get_cls(name, fallback_cls=conf.raw_layer): 321 """ 322 Returns class named "name" if it exists, fallback_cls otherwise. 323 """ 324 325 return globals().get(name, fallback_cls) 326 327 328# 329# Common dictionaries 330# 331 332_bgp_message_types = { 333 0: "NONE", 334 1: "OPEN", 335 2: "UPDATE", 336 3: "NOTIFICATION", 337 4: "KEEPALIVE", 338 5: "ROUTE-REFRESH" 339} 340 341 342# 343# AFIs 344# 345 346address_family_identifiers = { 347 0: "Reserved", 348 1: "IP (IP version 4)", 349 2: "IP6 (IP version 6)", 350 3: "NSAP", 351 4: "HDLC (8-bit multidrop)", 352 5: "BBN 1822", 353 6: "802 (includes all 802 media plus Ethernet \"canonical format\")", 354 7: "E.163", 355 8: "E.164 (SMDS, Frame Relay, ATM)", 356 9: "F.69 (Telex)", 357 10: "X.121 (X.25, Frame Relay)", 358 11: "IPX", 359 12: "Appletalk", 360 13: "Decnet IV", 361 14: "Banyan Vines", 362 15: "E.164 with NSAP format subaddress", # ANDY_MALIS 363 16: "DNS (Domain Name System)", 364 17: "Distinguished Name", # CHARLES_LYNN 365 18: "AS Number", # CHARLES_LYNN 366 19: "XTP over IP version 4", # MIKE_SAUL 367 20: "XTP over IP version 6", # MIKE_SAUL 368 21: "XTP native mode XTP", # MIKE_SAUL 369 22: "Fibre Channel World-Wide Port Name", # MARK_BAKKE 370 23: "Fibre Channel World-Wide Node Name", # MARK_BAKKE 371 24: "GWID", # SUBRA_HEGDE 372 25: "AFI for L2VPN information", # RFC 6074 373 26: "MPLS-TP Section Endpoint Identifier", # RFC 7212 374 27: "MPLS-TP LSP Endpoint Identifier", # RFC 7212 375 28: "MPLS-TP Pseudowire Endpoint Identifier", # RFC 7212 376 29: "MT IP: Multi-Topology IP version 4", # RFC 7307 377 30: "MT IPv6: Multi-Topology IP version 6", # RFC 7307 378 16384: "EIGRP Common Service Family", # DONNIE_SAVAGE 379 16385: "EIGRP IPv4 Service Family", # DONNIE_SAVAGE 380 16386: "EIGRP IPv6 Service Family", # DONNIE_SAVAGE 381 16387: "LISP Canonical Address Format (LCAF)", # DAVID_MEYER 382 16388: "BGP-LS", # RFC 7752 383 16389: "48-bit MAC", # RFC 7042 384 16390: "64-bit MAC", # RFC 7042 385 16391: "OUI", # draft-ietf-trill-ia-appsubtlv 386 16392: "MAC/24", # draft-ietf-trill-ia-appsubtlv 387 16393: "MAC/40", # draft-ietf-trill-ia-appsubtlv 388 16394: "IPv6/64", # draft-ietf-trill-ia-appsubtlv 389 16395: "RBridge Port ID", # draft-ietf-trill-ia-appsubtlv 390 16396: "TRILL Nickname", # RFC 7455 391 65535: "Reserved" 392} 393 394 395subsequent_afis = { 396 0: "Reserved", # RFC 4760 397 1: "Network Layer Reachability Information used for unicast forwarding", # RFC 4760 # noqa: E501 398 2: "Network Layer Reachability Information used for multicast forwarding", # RFC 4760 # noqa: E501 399 3: "Reserved", # RFC 4760 400 4: "Network Layer Reachability Information (NLRI) with MPLS Labels", # RFC 3107 # noqa: E501 401 5: "MCAST-VPN", # RFC 6514 402 6: "Network Layer Reachability Information used for Dynamic Placement of\ 403 Multi-Segment Pseudowires", # RFC 7267 404 7: "Encapsulation SAFI", # RFC 5512 405 8: "MCAST-VPLS", # RFC 7117 406 64: "Tunnel SAFI", # DRAFT-NALAWADE-KAPOOR-TUNNEL-SAFI-01 407 65: "Virtual Private LAN Service (VPLS)", # RFC 6074 408 66: "BGP MDT SAFI", # RFC 6037 409 67: "BGP 4over6 SAFI", # RFC 5747 410 68: "BGP 6over4 SAFI", # YONG_CUI 411 69: "Layer-1 VPN auto-discovery information", # RFC 5195 412 70: "BGP EVPNs", # RFC 7432 413 71: "BGP-LS", # RFC 7752 414 72: "BGP-LS-VPN", # RFC 7752 415 128: "MPLS-labeled VPN address", # RFC 4364 416 129: "Multicast for BGP/MPLS IP Virtual Private Networks (VPNs)", # RFC 6514 # noqa: E501 417 132: "Route Target constraint", # RFC 4684 418 133: "IPv4 dissemination of flow specification rules", # RFC 5575 419 134: "VPNv4 dissemination of flow specification rules", # RFC 5575 420 140: "VPN auto-discovery", # draft-ietf-l3vpn-bgpvpn-auto 421 255: "Reserved" # RFC 4760 422} 423 424 425# Used by _bgp_dispatcher to instantiate the appropriate class 426_bgp_cls_by_type = { 427 1: "BGPOpen", 428 2: "BGPUpdate", 429 3: "BGPNotification", 430 4: "BGPKeepAlive", 431 5: "BGPRouteRefresh", 432} 433 434 435# 436# Header 437# 438 439class BGPHeader(Packet): 440 """ 441 The header of any BGP message. 442 References: RFC 4271 443 """ 444 445 name = "HEADER" 446 fields_desc = [ 447 XBitField( 448 "marker", 449 0xffffffffffffffffffffffffffffffff, 450 0x80 451 ), 452 ShortField("len", None), 453 ByteEnumField("type", 4, _bgp_message_types) 454 ] 455 456 @classmethod 457 def dispatch_hook(cls, _pkt=None, *args, **kargs): 458 """ 459 Returns the right class for the given data. 460 """ 461 462 return _bgp_dispatcher(_pkt) 463 464 def post_build(self, p, pay): 465 if self.len is None: 466 length = len(p) 467 if pay: 468 length = length + len(pay) 469 p = p[:16] + struct.pack("!H", length) + p[18:] 470 return p + pay 471 472 def guess_payload_class(self, payload): 473 return _get_cls(_bgp_cls_by_type.get(self.type, conf.raw_layer), conf.raw_layer) # noqa: E501 474 475 476def _bgp_dispatcher(payload): 477 """ 478 Returns the right class for a given BGP message. 479 """ 480 481 cls = conf.raw_layer 482 483 # By default, calling BGP() will build a BGPHeader. 484 if payload is None: 485 cls = _get_cls("BGPHeader", conf.raw_layer) 486 487 else: 488 if len(payload) >= _BGP_HEADER_SIZE and\ 489 payload[:16] == _BGP_HEADER_MARKER: 490 491 # Get BGP message type 492 message_type = orb(payload[18]) 493 if message_type == 4: 494 cls = _get_cls("BGPKeepAlive") 495 else: 496 cls = _get_cls("BGPHeader") 497 498 return cls 499 500 501class BGP(Packet): 502 """ 503 Every BGP message inherits from this class. 504 """ 505 506 # 507 # BGP messages types 508 509 OPEN_TYPE = 1 510 UPDATE_TYPE = 2 511 NOTIFICATION_TYPE = 3 512 KEEPALIVE_TYPE = 4 513 ROUTEREFRESH_TYPE = 5 514 515 @classmethod 516 def dispatch_hook(cls, _pkt=None, *args, **kargs): 517 """ 518 Returns the right class for the given data. 519 """ 520 521 return _bgp_dispatcher(_pkt) 522 523 def guess_payload_class(self, p): 524 cls = None 525 if len(p) > 15 and p[:16] == _BGP_HEADER_MARKER: 526 cls = BGPHeader 527 return cls 528 529 530# 531# KEEPALIVE 532# 533 534class BGPKeepAlive(BGP, BGPHeader): 535 536 """ 537 KEEPALIVE message. 538 """ 539 540 name = "KEEPALIVE" 541 542 543# 544# OPEN 545# 546 547# 548# Optional Parameters Codes 549# 550 551optional_parameter_codes = { 552 0: "Reserved", 553 1: "Authentication (deprecated)", 554 2: "Capabilities" 555} 556 557 558# 559# Capabilities 560# 561 562_capabilities = { 563 0: "Reserved", # RFC 5492 564 1: "Multiprotocol Extensions for BGP-4", # RFC 2858 565 2: "Route Refresh Capability for BGP-4", # RFC 2918 566 3: "Outbound Route Filtering Capability", # RFC 5291 567 4: "Multiple routes to a destination capability", # RFC 3107 568 5: "Extended Next Hop Encoding", # RFC 5549 569 6: "BGP-Extended Message", # (TEMPORARY - registered 2015-09-30, expires 2016-09-30), # noqa: E501 570 # draft-ietf-idr-bgp-extended-messages 571 64: "Graceful Restart Capability", # RFC 4724 572 65: "Support for 4-octet AS number capability", # RFC 6793 573 66: "Deprecated (2003-03-06)", 574 67: "Support for Dynamic Capability (capability specific)", # draft-ietf-idr-dynamic-cap # noqa: E501 575 68: "Multisession BGP Capability", # draft-ietf-idr-bgp-multisession 576 69: "ADD-PATH Capability", # RFC-ietf-idr-add-paths-15 577 70: "Enhanced Route Refresh Capability", # RFC 7313 578 71: "Long-Lived Graceful Restart (LLGR) Capability", # draft-uttaro-idr-bgp-persistence # noqa: E501 579 73: "FQDN Capability", # draft-walton-bgp-hostname-capability 580 128: "Route Refresh Capability for BGP-4 (Cisco)", # Cisco also uses 128 for RR capability # noqa: E501 581 130: "Outbound Route Filtering Capability (Cisco)", # Cisco also uses 130 for ORF capability # noqa: E501 582} 583 584 585_capabilities_objects = { 586 0x01: "BGPCapMultiprotocol", # RFC 2858 587 0x02: "BGPCapGeneric", # RFC 2918 588 0x03: "BGPCapORF", # RFC 5291 589 0x40: "BGPCapGracefulRestart", # RFC 4724 590 0x41: "BGPCapFourBytesASN", # RFC 4893 591 0x46: "BGPCapGeneric", # Enhanced Route Refresh Capability, RFC 7313 592 0x82: "BGPCapORF", # ORF / RFC 5291 (Cisco) 593} 594 595 596def _register_cls(registry, cls): 597 registry[cls.__name__] = cls 598 return cls 599 600 601_capabilities_registry = {} 602 603 604def _bgp_capability_dispatcher(payload): 605 """ 606 Returns the right class for a given BGP capability. 607 """ 608 609 cls = _capabilities_registry["BGPCapGeneric"] 610 611 # By default, calling BGPCapability() will build a "generic" capability. 612 if payload is None: 613 cls = _capabilities_registry["BGPCapGeneric"] 614 615 else: 616 length = len(payload) 617 if length >= _BGP_CAPABILITY_MIN_SIZE: 618 code = orb(payload[0]) 619 cls = _get_cls(_capabilities_objects.get(code, "BGPCapGeneric")) 620 621 return cls 622 623 624class _BGPCap_metaclass(type): 625 def __new__(cls, clsname, bases, attrs): 626 newclass = super(_BGPCap_metaclass, cls).__new__( 627 cls, clsname, bases, attrs) 628 _register_cls(_capabilities_registry, newclass) 629 return newclass 630 631 632class _BGPCapability_metaclass(_BGPCap_metaclass, Packet_metaclass): 633 pass 634 635 636class BGPCapability(Packet, metaclass=_BGPCapability_metaclass): 637 """ 638 Generic BGP capability. 639 """ 640 641 @classmethod 642 def dispatch_hook(cls, _pkt=None, *args, **kargs): 643 """ 644 Returns the right class for the given data. 645 """ 646 647 return _bgp_capability_dispatcher(_pkt) 648 649 def pre_dissect(self, s): 650 """ 651 Check that the payload is long enough (at least 2 bytes). 652 """ 653 length = len(s) 654 if length < _BGP_CAPABILITY_MIN_SIZE: 655 err = " ({}".format(length) + " is < _BGP_CAPABILITY_MIN_SIZE " 656 err += "({})).".format(_BGP_CAPABILITY_MIN_SIZE) 657 raise _BGPInvalidDataException(err) 658 return s 659 660 def post_build(self, p, pay): 661 length = 0 662 if self.length is None: 663 # capability packet length - capability code (1 byte) - 664 # capability length (1 byte) 665 length = len(p) - 2 666 p = p[:1] + chb(length) + p[2:] 667 return p + pay 668 669 670class BGPCapGeneric(BGPCapability): 671 """ 672 This class provides an implementation of a generic capability. 673 """ 674 675 name = "BGP Capability" 676 match_subclass = True 677 fields_desc = [ 678 ByteEnumField("code", 0, _capabilities), 679 FieldLenField("length", None, fmt="B", length_of="cap_data"), 680 StrLenField("cap_data", '', 681 length_from=lambda p: p.length, max_length=255), 682 ] 683 684 685# 686# Multiprotocol Extensions for BGP-4 687# 688 689class BGPCapMultiprotocol(BGPCapability): 690 """ 691 This class provides an implementation of the Multiprotocol 692 capability. 693 References: RFC 4760 694 """ 695 696 name = "Multiprotocol Extensions for BGP-4" 697 match_subclass = True 698 fields_desc = [ 699 ByteEnumField("code", 1, _capabilities), 700 ByteField("length", 4), 701 ShortEnumField("afi", 0, address_family_identifiers), 702 ByteField("reserved", 0), 703 ByteEnumField("safi", 0, subsequent_afis) 704 ] 705 706 707# 708# Outbound Route Filtering Capability for BGP-4 709# 710 711_orf_types = { 712 0: "Reserved", # RFC 5291 713 64: "Address Prefix ORF", # RFC 5292 714 65: "CP-ORF", # RFC 7543 715} 716 717 718send_receive_values = { 719 1: "receive", 720 2: "send", 721 3: "receive + send" 722} 723 724 725class BGPCapORFBlock(Packet): 726 """ 727 The "ORFBlock" is made of <AFI, rsvd, SAFI, Number of ORFs, and 728 <ORF Type, Send/Receive> entries. 729 """ 730 731 class ORFTuple(Packet): 732 """ 733 Packet handling <ORF Types, Send/Receive> tuples. 734 """ 735 736 # (ORF Type (1 octet) / Send/Receive (1 octet)) .... 737 name = "ORF Type" 738 fields_desc = [ 739 ByteEnumField("orf_type", 0, _orf_types), 740 ByteEnumField("send_receive", 0, send_receive_values) 741 ] 742 743 name = "ORF Capability Entry" 744 fields_desc = [ 745 ShortEnumField("afi", 0, address_family_identifiers), 746 ByteField("reserved", 0), 747 ByteEnumField("safi", 0, subsequent_afis), 748 FieldLenField( 749 "orf_number", 750 None, 751 count_of="entries", 752 fmt="!B" 753 ), 754 PacketListField( 755 "entries", 756 [], 757 ORFTuple, 758 count_from=lambda p: p.orf_number 759 ) 760 ] 761 762 def post_build(self, p, pay): 763 count = None 764 if self.orf_number is None: 765 count = len(self.entries) # orf_type (1 byte) + send_receive (1 byte) # noqa: E501 766 p = p[:4] + struct.pack("!B", count) + p[5:] 767 return p + pay 768 769 770class BGPCapORFBlockPacketListField(PacketListField): 771 """ 772 Handles lists of BGPCapORFBlocks. 773 """ 774 775 def getfield(self, pkt, s): 776 lst = [] 777 length = None 778 779 if self.length_from is not None: 780 length = self.length_from(pkt) 781 remain = s 782 if length is not None: 783 remain = s[:length] 784 785 while remain: 786 # block length: afi (2 bytes) + reserved (1 byte) + safi (1 byte) + 787 # orf_number (1 byte) + entries (2 bytes * orf_number) 788 orf_number = orb(remain[4]) 789 entries_length = orf_number * 2 790 current = remain[:5 + entries_length] 791 remain = remain[5 + entries_length:] 792 packet = self.m2i(pkt, current) 793 lst.append(packet) 794 795 return remain, lst 796 797 798class BGPCapORF(BGPCapability): 799 """ 800 This class provides an implementation of the Outbound Route Filtering 801 capability. 802 References: RFC 5291 803 """ 804 805 name = "Outbound Route Filtering Capability" 806 match_subclass = True 807 fields_desc = [ 808 ByteEnumField("code", 3, _capabilities), 809 ByteField("length", None), 810 BGPCapORFBlockPacketListField( 811 "orf", 812 [], 813 BGPCapORFBlock, 814 length_from=lambda p: p.length 815 ) 816 ] 817 818 819# 820# Graceful Restart capability 821# 822 823gr_address_family_flags = { 824 128: "Forwarding state preserved (0x80: F bit set)" 825} 826 827 828class BGPCapGracefulRestart(BGPCapability): 829 """ 830 This class provides an implementation of the Graceful Restart 831 capability. 832 References: RFC 4724 833 """ 834 835 class GRTuple(Packet): 836 837 """Tuple <AFI, SAFI, Flags for address family>""" 838 name = "<AFI, SAFI, Flags for address family>" 839 fields_desc = [ShortEnumField("afi", 0, address_family_identifiers), 840 ByteEnumField("safi", 0, subsequent_afis), 841 ByteEnumField("flags", 0, gr_address_family_flags)] 842 843 name = "Graceful Restart Capability" 844 match_subclass = True 845 fields_desc = [ByteEnumField("code", 64, _capabilities), 846 ByteField("length", None), 847 BitField("restart_flags", 0, 4), 848 BitField("restart_time", 0, 12), 849 PacketListField("entries", [], GRTuple)] 850 851 852# 853# Support for 4-octet AS number capability 854# 855 856class BGPCapFourBytesASN(BGPCapability): 857 """ 858 This class provides an implementation of the 4-octet AS number 859 capability. 860 References: RFC 4893 861 """ 862 863 name = "Support for 4-octet AS number capability" 864 match_subclass = True 865 fields_desc = [ByteEnumField("code", 65, _capabilities), 866 ByteField("length", 4), 867 IntField("asn", 0)] 868 869 870# 871# Authentication Information optional parameter. 872# 873 874class BGPAuthenticationInformation(Packet): 875 876 """ 877 Provides an implementation of the Authentication Information optional 878 parameter, which is now obsolete. 879 References: RFC 1771, RFC 1654, RFC 4271 880 """ 881 882 name = "BGP Authentication Data" 883 fields_desc = [ByteField("authentication_code", 0), 884 StrField("authentication_data", None)] 885 886 887# 888# Optional Parameter. 889# 890 891 892class BGPOptParamPacketListField(PacketListField): 893 """ 894 PacketListField handling the optional parameters (OPEN message). 895 """ 896 897 def getfield(self, pkt, s): 898 lst = [] 899 900 length = 0 901 if self.length_from is not None: 902 length = self.length_from(pkt) 903 remain = s 904 if length is not None: 905 remain, ret = s[:length], s[length:] 906 907 while remain: 908 param_len = orb(remain[1]) # Get param length 909 current = remain[:2 + param_len] 910 remain = remain[2 + param_len:] 911 packet = self.m2i(pkt, current) 912 lst.append(packet) 913 914 return remain + ret, lst 915 916 917class BGPOptParam(Packet): 918 """ 919 Provides an implementation the OPEN message optional parameters. 920 References: RFC 4271 921 """ 922 923 name = "Optional parameter" 924 fields_desc = [ 925 ByteEnumField("param_type", 2, optional_parameter_codes), 926 ByteField("param_length", None), 927 ConditionalField( 928 PacketField( 929 "param_value", 930 None, 931 BGPCapability 932 ), 933 lambda p: p.param_type == 2 934 ), 935 # It"s obsolete, but one can use it provided that 936 # param_type == 1. 937 ConditionalField( 938 PacketField( 939 "authentication_data", 940 None, 941 BGPAuthenticationInformation 942 ), 943 lambda p: p.param_type == 1 944 ) 945 ] 946 947 def post_build(self, p, pay): 948 length = None 949 packet = p 950 if self.param_length is None: 951 if self.param_value is None and self.authentication_data is None: 952 length = 0 953 else: 954 length = len(p) - \ 955 2 # parameter type (1 byte) - parameter length (1 byte) 956 packet = p[:1] + chb(length) 957 if (self.param_type == 2 and self.param_value is not None) or\ 958 (self.param_type == 1 and self.authentication_data is not None): # noqa: E501 959 packet = packet + p[2:] 960 961 return packet + pay 962 963 964# 965# OPEN 966# 967 968class BGPOpen(BGP): 969 """ 970 OPEN messages are exchanged in order to open a new BGP session. 971 References: RFC 4271 972 """ 973 974 name = "OPEN" 975 fields_desc = [ 976 ByteField("version", 4), 977 ShortField("my_as", 0), 978 ShortField("hold_time", 0), 979 IPField("bgp_id", "0.0.0.0"), 980 FieldLenField( 981 "opt_param_len", 982 None, 983 length_of="opt_params", 984 fmt="!B" 985 ), 986 BGPOptParamPacketListField( 987 "opt_params", 988 [], 989 BGPOptParam, 990 length_from=lambda p: p.opt_param_len 991 ) 992 ] 993 994 def post_build(self, p, pay): 995 if self.opt_param_len is None: 996 length = len(p) - 10 # 10 is regular length with no additional 997 # options 998 p = p[:9] + struct.pack("!B", length) + p[10:] 999 return p + pay 1000 1001 1002# 1003# UPDATE 1004# 1005 1006# 1007# Path attributes 1008# 1009 1010# 1011# Dictionaries 1012 1013path_attributes = { 1014 0: "Reserved", 1015 1: "ORIGIN", # RFC 4271 1016 2: "AS_PATH", # RFC 4271 1017 3: "NEXT_HOP", # RFC 4271 1018 4: "MULTI_EXIT_DISC", # RFC 4271 1019 5: "LOCAL_PREF", # RFC 4271 1020 6: "ATOMIC_AGGREGATE", # RFC 4271 1021 7: "AGGREGATOR", # RFC 4271 1022 8: "COMMUNITY", # RFC 1997 1023 9: "ORIGINATOR_ID", # RFC 4456 1024 10: "CLUSTER_LIST", # RFC 4456 1025 11: "DPA (deprecated)", # RFC 6938 1026 12: "ADVERTISER (Historic) (deprecated)", # RFC 4223, RFC 6938 1027 13: "RCID_PATH / CLUSTER_ID (Historic) (deprecated)", # RFC 4223, RFC 6938 1028 14: "MP_REACH_NLRI", # RFC 4760 1029 15: "MP_UNREACH_NLRI", # RFC 4760 1030 16: "EXTENDED COMMUNITIES", # RFC 4360 1031 17: "AS4_PATH", # RFC 6793 1032 18: "AS4_AGGREGATOR", # RFC 6793 1033 19: "SAFI Specific Attribute (SSA) (deprecated)", # draft-kapoor-nalawade-idr-bgp-ssa-00, # noqa: E501 1034 # draft-nalawade-idr-mdt-safi-00, draft-wijnands-mt-discovery-00 1035 20: "Connector Attribute (deprecated)", # RFC 6037 1036 21: "AS_PATHLIMIT (deprecated)", # draft-ietf-idr-as-pathlimit 1037 22: "PMSI_TUNNEL", # RFC 6514 1038 23: "Tunnel Encapsulation Attribute", # RFC 5512 1039 24: "Traffic Engineering", # RFC 5543 1040 25: "IPv6 Address Specific Extended Community", # RFC 5701 1041 26: "AIGP", # RFC 7311 1042 27: "PE Distinguisher Labels", # RFC 6514 1043 28: "BGP Entropy Label Capability Attribute (deprecated)", # RFC 6790, RFC 7447 # noqa: E501 1044 29: "BGP-LS Attribute", # RFC 7752 1045 32: "LARGE_COMMUNITY", # RFC 8092, RFC 8195 1046 40: "BGP Prefix-SID", # (TEMPORARY - registered 2015-09-30, expires 2016-09-30) # noqa: E501 1047 # draft-ietf-idr-bgp-prefix-sid 1048 128: "ATTR_SET", # RFC 6368 1049 255: "Reserved for development" 1050} 1051 1052# http://www.iana.org/assignments/bgp-parameters/bgp-parameters.xml 1053attributes_flags = { 1054 1: 0x40, # ORIGIN 1055 2: 0x40, # AS_PATH 1056 3: 0x40, # NEXT_HOP 1057 4: 0x80, # MULTI_EXIT_DISC 1058 5: 0x40, # LOCAL_PREF 1059 6: 0x40, # ATOMIC_AGGREGATE 1060 7: 0xc0, # AGGREGATOR 1061 8: 0xc0, # COMMUNITIES (RFC 1997) 1062 9: 0x80, # ORIGINATOR_ID (RFC 4456) 1063 10: 0x80, # CLUSTER_LIST (RFC 4456) 1064 11: 0xc0, # DPA (RFC 6938) 1065 12: 0x80, # ADVERTISER (RFC 1863, RFC 4223) 1066 13: 0x80, # RCID_PATH (RFC 1863, RFC 4223) 1067 14: 0x80, # MP_REACH_NLRI (RFC 4760) 1068 15: 0x80, # MP_UNREACH_NLRI (RFC 4760) 1069 16: 0xc0, # EXTENDED_COMMUNITIES (RFC 4360) 1070 17: 0xc0, # AS4_PATH (RFC 6793) 1071 18: 0xc0, # AS4_AGGREGATOR (RFC 6793) 1072 19: 0xc0, # SSA (draft-kapoor-nalawade-idr-bgp-ssa-00) 1073 20: 0xc0, # Connector (RFC 6037) 1074 21: 0xc0, # AS_PATHLIMIT (draft-ietf-idr-as-pathlimit) 1075 22: 0xc0, # PMSI_TUNNEL (RFC 6514) 1076 23: 0xc0, # Tunnel Encapsulation (RFC 5512) 1077 24: 0x80, # Traffic Engineering (RFC 5543) 1078 25: 0xc0, # IPv6 Address Specific Extended Community (RFC 5701) 1079 26: 0x80, # AIGP (RFC 7311) 1080 27: 0xc0, # PE Distinguisher Labels (RFC 6514) 1081 28: 0xc0, # BGP Entropy Label Capability Attribute 1082 29: 0x80, # BGP-LS Attribute 1083 32: 0xc0, # LARGE_COMMUNITY 1084 40: 0xc0, # BGP Prefix-SID 1085 128: 0xc0 # ATTR_SET (RFC 6368) 1086} 1087 1088 1089class BGPPathAttrPacketListField(PacketListField): 1090 """ 1091 PacketListField handling the path attributes (UPDATE message). 1092 """ 1093 1094 def getfield(self, pkt, s): 1095 lst = [] 1096 length = 0 1097 1098 if self.length_from is not None: 1099 length = self.length_from(pkt) 1100 ret = "" 1101 remain = s 1102 if length is not None: 1103 remain, ret = s[:length], s[length:] 1104 1105 while remain: 1106 # 1107 # Get the path attribute flags 1108 flags = orb(remain[0]) 1109 1110 attr_len = 0 1111 if has_extended_length(flags): 1112 attr_len = struct.unpack("!H", remain[2:4])[0] 1113 current = remain[:4 + attr_len] 1114 remain = remain[4 + attr_len:] 1115 else: 1116 attr_len = orb(remain[2]) 1117 current = remain[:3 + attr_len] 1118 remain = remain[3 + attr_len:] 1119 1120 packet = self.m2i(pkt, current) 1121 lst.append(packet) 1122 1123 return remain + ret, lst 1124 1125 1126# 1127# ORIGIN 1128# 1129 1130class BGPPAOrigin(Packet): 1131 1132 """ 1133 Packet handling the ORIGIN attribute value. 1134 References: RFC 4271 1135 """ 1136 1137 name = "ORIGIN" 1138 fields_desc = [ 1139 ByteEnumField("origin", 0, {0: "IGP", 1: "EGP", 2: "INCOMPLETE"})] 1140 1141 1142# 1143# AS_PATH (2 bytes and 4 bytes) 1144# 1145 1146as_path_segment_types = { 1147 # RFC 4271 1148 1: "AS_SET", 1149 2: "AS_SEQUENCE", 1150 1151 # RFC 5065 1152 3: "AS_CONFED_SEQUENCE", 1153 4: "AS_CONFED_SET" 1154} 1155 1156 1157class ASPathSegmentPacketListField(PacketListField): 1158 """ 1159 PacketListField handling AS_PATH segments. 1160 """ 1161 1162 def getfield(self, pkt, s): 1163 lst = [] 1164 remain = s 1165 1166 while remain: 1167 # 1168 # Get the segment length 1169 segment_length = orb(remain[1]) 1170 1171 if bgp_module_conf.use_2_bytes_asn: 1172 current = remain[:2 + segment_length * 2] 1173 remain = remain[2 + segment_length * 2:] 1174 else: 1175 current = remain[:2 + segment_length * 4] 1176 remain = remain[2 + segment_length * 4:] 1177 1178 packet = self.m2i(pkt, current) 1179 lst.append(packet) 1180 1181 return remain, lst 1182 1183 1184class BGPPAASPath(Packet): 1185 """ 1186 Packet handling the AS_PATH attribute value (2 bytes ASNs, for old 1187 speakers). 1188 References: RFC 4271, RFC 5065 1189 """ 1190 1191 AS_TRANS = 23456 1192 1193 class ASPathSegment(Packet): 1194 """ 1195 Provides an implementation for AS_PATH segments with 2 bytes ASNs. 1196 """ 1197 1198 fields_desc = [ 1199 ByteEnumField("segment_type", 2, as_path_segment_types), 1200 ByteField("segment_length", None), 1201 FieldListField("segment_value", [], ShortField("asn", 0)) 1202 ] 1203 1204 def post_build(self, p, pay): 1205 segment_len = self.segment_length 1206 if segment_len is None: 1207 segment_len = len(self.segment_value) 1208 p = p[:1] + chb(segment_len) + p[2:] 1209 1210 return p + pay 1211 1212 name = "AS_PATH (RFC 4271)" 1213 fields_desc = [ 1214 ASPathSegmentPacketListField("segments", [], ASPathSegment)] 1215 1216 1217class BGPPAAS4BytesPath(Packet): 1218 """ 1219 Packet handling the AS_PATH attribute value (4 bytes ASNs, for new 1220 speakers -> ASNs are encoded as IntFields). 1221 References: RFC 4893 1222 """ 1223 1224 class ASPathSegment(Packet): 1225 """ 1226 Provides an implementation for AS_PATH segments with 4 bytes ASNs. 1227 """ 1228 1229 fields_desc = [ByteEnumField("segment_type", 2, as_path_segment_types), 1230 ByteField("segment_length", None), 1231 FieldListField("segment_value", [], IntField("asn", 0))] 1232 1233 def post_build(self, p, pay): 1234 segment_len = self.segment_length 1235 if segment_len is None: 1236 segment_len = len(self.segment_value) 1237 p = p[:1] + chb(segment_len) + p[2:] 1238 1239 return p + pay 1240 1241 name = "AS_PATH (RFC 4893)" 1242 fields_desc = [ 1243 ASPathSegmentPacketListField("segments", [], ASPathSegment)] 1244 1245 1246# 1247# NEXT_HOP 1248# 1249 1250class BGPPANextHop(Packet): 1251 """ 1252 Packet handling the NEXT_HOP attribute value. 1253 References: RFC 4271 1254 """ 1255 1256 name = "NEXT_HOP" 1257 fields_desc = [IPField("next_hop", "0.0.0.0")] 1258 1259 1260# 1261# MULTI_EXIT_DISC 1262# 1263 1264class BGPPAMultiExitDisc(Packet): 1265 """ 1266 Packet handling the MULTI_EXIT_DISC attribute value. 1267 References: RFC 4271 1268 """ 1269 1270 name = "MULTI_EXIT_DISC" 1271 fields_desc = [IntField("med", 0)] 1272 1273 1274# 1275# LOCAL_PREF 1276# 1277 1278class BGPPALocalPref(Packet): 1279 """ 1280 Packet handling the LOCAL_PREF attribute value. 1281 References: RFC 4271 1282 """ 1283 1284 name = "LOCAL_PREF" 1285 fields_desc = [IntField("local_pref", 0)] 1286 1287 1288# 1289# ATOMIC_AGGREGATE 1290# 1291 1292class BGPPAAtomicAggregate(Packet): 1293 """ 1294 Packet handling the ATOMIC_AGGREGATE attribute value. 1295 References: RFC 4271 1296 """ 1297 1298 name = "ATOMIC_AGGREGATE" 1299 1300 1301# 1302# AGGREGATOR 1303# 1304 1305class BGPPAAggregator(Packet): 1306 """ 1307 Packet handling the AGGREGATOR attribute value. 1308 References: RFC 4271 1309 """ 1310 1311 name = "AGGREGATOR" 1312 fields_desc = [ShortField("aggregator_asn", 0), 1313 IPField("speaker_address", "0.0.0.0")] 1314 1315 1316# 1317# COMMUNITIES 1318# 1319 1320# http://www.iana.org/assignments/bgp-well-known-communities/bgp-well-known-communities.xml 1321well_known_communities = { 1322 0xFFFFFF01: "NO_EXPORT", # RFC 1997 1323 0xFFFFFF02: "NO_ADVERTISE", # RFC 1997 1324 0xFFFFFF03: "NO_EXPORT_SUBCONFED", # RFC 1997 1325 0xFFFFFF04: "NOPEER", # RFC 3765 1326 0xFFFF0000: "planned-shut", # draft-francois-bgp-gshut 1327 0xFFFF0001: "ACCEPT-OWN", # RFC 7611 1328 0xFFFF0002: "ROUTE_FILTER_TRANSLATED_v4", # draft-l3vpn-legacy-rtc 1329 0xFFFF0003: "ROUTE_FILTER_v4", # draft-l3vpn-legacy-rtc 1330 0xFFFF0004: "ROUTE_FILTER_TRANSLATED_v6", # draft-l3vpn-legacy-rtc 1331 0xFFFF0005: "ROUTE_FILTER_v6", # draft-l3vpn-legacy-rtc 1332 0xFFFF0006: "LLGR_STALE", # draft-uttaro-idr-bgp-persistence 1333 0xFFFF0007: "NO_LLGR", # draft-uttaro-idr-bgp-persistence 1334 0xFFFF0008: "accept-own-nexthop", # Ashutosh_Grewal 1335} 1336 1337 1338class BGPPACommunity(Packet): 1339 """ 1340 Packet handling the COMMUNITIES attribute value. 1341 References: RFC 1997 1342 """ 1343 1344 name = "COMMUNITIES" 1345 fields_desc = [IntEnumField("community", 0, well_known_communities)] 1346 1347 1348# 1349# ORIGINATOR_ID 1350# 1351 1352class BGPPAOriginatorID(Packet): 1353 """ 1354 Packet handling the ORIGINATOR_ID attribute value. 1355 References: RFC 4456 1356 """ 1357 1358 name = "ORIGINATOR_ID" 1359 fields_desc = [IPField("originator_id", "0.0.0.0")] 1360 1361 1362# 1363# CLUSTER_LIST 1364# 1365 1366class BGPPAClusterList(Packet): 1367 """ 1368 Packet handling the CLUSTER_LIST attribute value. 1369 References: RFC 4456 1370 """ 1371 1372 name = "CLUSTER_LIST" 1373 fields_desc = [ 1374 FieldListField("cluster_list", [], IntField("cluster_id", 0))] 1375 1376 1377# 1378# EXTENDED COMMUNITIES (RFC 4360) 1379# 1380 1381# BGP Transitive Extended Community Types 1382# http://www.iana.org/assignments/bgp-extended-communities/bgp-extended-communities.xhtml#transitive 1383_ext_comm_types = { 1384 0x00: "Transitive Two-Octet AS-Specific Extended Community", # RFC 7153 1385 0x01: "Transitive IPv4-Address-Specific Extended Community", # RFC 7153 1386 0x02: "Transitive Four-Octet AS-Specific Extended Community", # RFC 7153 1387 0x03: "Transitive Opaque Extended Community", # RFC 7153 1388 0x04: "QoS Marking", # Thomas_Martin_Knoll 1389 0x05: "CoS Capability", # Thomas_Martin_Knoll 1390 0x06: "EVPN", # RFC 7153 1391 0x07: "Unassigned", 1392 0x08: "Flow spec redirect/mirror to IP next-hop", # draft-simpson-idr-flowspec-redirect # noqa: E501 1393 1394 # BGP Non-Transitive Extended Community Types 1395 0x40: "Non-Transitive Two-Octet AS-Specific Extended Community", # RFC 7153 # noqa: E501 1396 0x41: "Non-Transitive IPv4-Address-Specific Extended Community", # RFC 7153 # noqa: E501 1397 0x42: "Non-Transitive Four-Octet AS-Specific Extended Community", # RFC 7153 # noqa: E501 1398 0x43: "Non-Transitive Opaque Extended Community", # RFC 7153 1399 0x44: "QoS Marking", # Thomas_Martin_Knoll 1400 1401 0x80: "Generic Transitive Experimental Use Extended Community", # RFC 7153 1402 0x81: "Generic Transitive Experimental Use Extended Community Part 2", # RFC 7674 # noqa: E501 1403 0x82: "Generic Transitive Experimental Use Extended Community Part 3", # RFC 7674 # noqa: E501 1404} 1405 1406# EVPN Extended Community Sub-Types 1407_ext_comm_evpn_subtypes = { 1408 0x00: "MAC Mobility", # RFC 7432 1409 0x01: "ESI Label", # RFC 7432 1410 0x02: "ES-Import Route Target", # RFC 7432 1411 0x03: "EVPN Router\"s MAC Extended Community", 1412 # draft-sajassi-l2vpn-evpn-inter-subnet-forwarding 1413 0x04: "Layer 2 Extended Community", # draft-ietf-bess-evpn-vpws 1414 0x05: "E-TREE Extended Community", # draft-ietf-bess-evpn-etree 1415 0x06: "DF Election Extended Community", # draft-ietf-bess-evpn-df-election 1416 0x07: "I-SID Extended Community", # draft-sajassi-bess-evpn-virtual-eth-segment # noqa: E501 1417} 1418 1419# Transitive Two-Octet AS-Specific Extended Community Sub-Types 1420_ext_comm_trans_two_octets_as_specific_subtypes = { 1421 0x02: "Route Target", # RFC 4360 1422 0x03: "Route Origin", # RFC 4360 1423 0x04: "Unassigned", # RFC 4360 1424 0x05: "OSPF Domain Identifier", # RFC 4577 1425 0x08: "BGP Data Collection", # RFC 4384 1426 0x09: "Source AS", # RFC 6514 1427 0x0a: "L2VPN Identifier", # RFC 6074 1428 0x0010: "Cisco VPN-Distinguisher", # Eric_Rosen 1429} 1430 1431# Non-Transitive Two-Octet AS-Specific Extended Community Sub-Types 1432_ext_comm_non_trans_two_octets_as_specific_subtypes = { 1433 0x04: "Link Bandwidth Extended Community", # draft-ietf-idr-link-bandwidth-00 # noqa: E501 1434 0x80: "Virtual-Network Identifier Extended Community", 1435 # draft-drao-bgp-l3vpn-virtual-network-overlays 1436} 1437 1438# Transitive Four-Octet AS-Specific Extended Community Sub-Types 1439_ext_comm_trans_four_octets_as_specific_subtypes = { 1440 0x02: "Route Target", # RFC 5668 1441 0x03: "Route Origin", # RFC 5668 1442 0x04: "Generic", # draft-ietf-idr-as4octet-extcomm-generic-subtype 1443 0x05: "OSPF Domain Identifier", # RFC 4577 1444 0x08: "BGP Data Collection", # RFC 4384 1445 0x09: "Source AS", # RFC 6514 1446 0x10: "Cisco VPN Identifier", # Eric_Rosen 1447} 1448 1449# Non-Transitive Four-Octet AS-Specific Extended Community Sub-Types 1450_ext_comm_non_trans_four_octets_as_specific_subtypes = { 1451 0x04: "Generic", # draft-ietf-idr-as4octet-extcomm-generic-subtype 1452} 1453 1454# Transitive IPv4-Address-Specific Extended Community Sub-Types 1455_ext_comm_trans_ipv4_addr_specific_subtypes = { 1456 0x02: "Route Target", # RFC 4360 1457 0x03: "Route Origin", # RFC 4360 1458 0x05: "OSPF Domain Identifier", # RFC 4577 1459 0x07: "OSPF Route ID", # RFC 4577 1460 0x0a: "L2VPN Identifier", # RFC 6074 1461 0x0b: "VRF Route Import", # RFC 6514 1462 0x0c: "Flow-spec Redirect to IPv4", # draft-ietf-idr-flowspec-redirect 1463 0x10: "Cisco VPN-Distinguisher", # Eric_Rosen 1464 0x12: "Inter-Area P2MP Segmented Next-Hop", # RFC 7524 1465} 1466 1467# Non-Transitive IPv4-Address-Specific Extended Community Sub-Types 1468_ext_comm_non_trans_ipv4_addr_specific_subtypes = {} 1469 1470# Transitive Opaque Extended Community Sub-Types 1471_ext_comm_trans_opaque_subtypes = { 1472 0x01: "Cost Community", # draft-ietf-idr-custom-decision 1473 0x03: "CP-ORF", # RFC 7543 1474 0x04: "Extranet Source Extended Community", # RFC 7900 1475 0x05: "Extranet Separation Extended Community", # RFC 7900 1476 0x06: "OSPF Route Type", # RFC 4577 1477 0x07: "Additional PMSI Tunnel Attribute Flags", # RFC 7902 1478 0x0b: "Color Extended Community", # RFC 5512 1479 0x0c: "Encapsulation Extended Community", # RFC 5512 1480 0x0d: "Default Gateway", # Yakov_Rekhter 1481 0x0e: "Point-to-Point-to-Multipoint (PPMP) Label", # Rishabh_Parekh 1482 0x13: "Route-Target Record", # draft-ietf-bess-service-chaining 1483 0x14: "Consistent Hash Sort Order", # draft-ietf-bess-service-chaining 1484} 1485 1486# Non-Transitive Opaque Extended Community Sub-Types 1487_ext_comm_non_trans_opaque_subtypes = { 1488 0x00: "BGP Origin Validation State", # draft-ietf-sidr-origin-validation-signaling # noqa: E501 1489 0x01: "Cost Community", # draft-ietf-idr-custom-decision 1490} 1491 1492# Generic Transitive Experimental Use Extended Community Sub-Types 1493_ext_comm_generic_transitive_exp_subtypes = { 1494 0x00: "OSPF Route Type (deprecated)", # RFC 4577 1495 0x01: "OSPF Router ID (deprecated)", # RFC 4577 1496 0x05: "OSPF Domain Identifier (deprecated)", # RFC 4577 1497 0x06: "Flow spec traffic-rate", # RFC 5575 1498 0x07: "Flow spec traffic-action", # RFC 5575 1499 0x08: "Flow spec redirect AS-2byte format", # RFC 5575, RFC 7674 1500 0x09: "Flow spec traffic-remarking", # RFC 5575 1501 0x0a: "Layer2 Info Extended Community", # RFC 4761 1502 0x0b: "E-Tree Info", # RFC 7796 1503} 1504 1505# Generic Transitive Experimental Use Extended Community Part 2 Sub-Types 1506_ext_comm_generic_transitive_exp_part2_subtypes = { 1507 0x08: "Flow spec redirect IPv4 format", # RFC 7674 1508} 1509 1510# Generic Transitive Experimental Use Extended Community Part 3 Sub-Types 1511_ext_comm_generic_transitive_exp_part3_subtypes = { 1512 0x08: "Flow spec redirect AS-4byte format", # RFC 7674 1513} 1514 1515# Traffic Action Fields 1516_ext_comm_traffic_action_fields = { 1517 47: "Terminal Action", # RFC 5575 1518 46: "Sample", # RFC 5575 1519} 1520 1521# Transitive IPv6-Address-Specific Extended Community Types 1522_ext_comm_trans_ipv6_addr_specific_types = { 1523 0x0002: "Route Target", # RFC 5701 1524 0x0003: "Route Origin", # RFC 5701 1525 0x0004: "OSPFv3 Route Attributes (DEPRECATED)", # RFC 6565 1526 0x000b: "VRF Route Import", # RFC 6515, RFC 6514 1527 0x000c: "Flow-spec Redirect to IPv6", # draft-ietf-idr-flowspec-redirect-ip # noqa: E501 1528 0x0010: "Cisco VPN-Distinguisher", # Eric_Rosen 1529 0x0011: "UUID-based Route Target", # Dhananjaya_Rao 1530 0x0012: "Inter-Area P2MP Segmented Next-Hop", # RFC 7524 1531} 1532 1533# Non-Transitive IPv6-Address-Specific Extended Community Types 1534_ext_comm_non_trans_ipv6_addr_specific_types = {} 1535 1536 1537_ext_comm_subtypes_classes = { 1538 0x00: _ext_comm_trans_two_octets_as_specific_subtypes, 1539 0x01: _ext_comm_trans_ipv4_addr_specific_subtypes, 1540 0x02: _ext_comm_trans_four_octets_as_specific_subtypes, 1541 0x03: _ext_comm_trans_opaque_subtypes, 1542 0x06: _ext_comm_evpn_subtypes, 1543 0x40: _ext_comm_non_trans_two_octets_as_specific_subtypes, 1544 0x41: _ext_comm_non_trans_ipv4_addr_specific_subtypes, 1545 0x42: _ext_comm_non_trans_four_octets_as_specific_subtypes, 1546 0x43: _ext_comm_non_trans_opaque_subtypes, 1547 0x80: _ext_comm_generic_transitive_exp_subtypes, 1548 0x81: _ext_comm_generic_transitive_exp_part2_subtypes, 1549 0x82: _ext_comm_generic_transitive_exp_part3_subtypes, 1550} 1551 1552 1553# 1554# Extended Community "templates" 1555# 1556 1557class BGPPAExtCommTwoOctetASSpecific(Packet): 1558 """ 1559 Packet handling the Two-Octet AS Specific Extended Community attribute 1560 value. 1561 References: RFC 4360 1562 """ 1563 1564 name = "Two-Octet AS Specific Extended Community" 1565 fields_desc = [ 1566 ShortField("global_administrator", 0), IntField("local_administrator", 0)] # noqa: E501 1567 1568 1569class BGPPAExtCommFourOctetASSpecific(Packet): 1570 """ 1571 Packet handling the Four-Octet AS Specific Extended Community 1572 attribute value. 1573 References: RFC 5668 1574 """ 1575 1576 name = "Four-Octet AS Specific Extended Community" 1577 fields_desc = [ 1578 IntField("global_administrator", 0), ShortField("local_administrator", 0)] # noqa: E501 1579 1580 1581class BGPPAExtCommIPv4AddressSpecific(Packet): 1582 """ 1583 Packet handling the IPv4 Address Specific Extended Community attribute 1584 value. 1585 References: RFC 4360 1586 """ 1587 1588 name = "IPv4 Address Specific Extended Community" 1589 fields_desc = [ 1590 IntField("global_administrator", 0), ShortField("local_administrator", 0)] # noqa: E501 1591 1592 1593class BGPPAExtCommOpaque(Packet): 1594 """ 1595 Packet handling the Opaque Extended Community attribute value. 1596 References: RFC 4360 1597 """ 1598 1599 name = "Opaque Extended Community" 1600 fields_desc = [StrFixedLenField("value", "", length=6)] 1601 1602 1603# 1604# FlowSpec related extended communities 1605# 1606 1607class BGPPAExtCommTrafficRate(Packet): 1608 """ 1609 Packet handling the (FlowSpec) "traffic-rate" extended community. 1610 References: RFC 5575 1611 """ 1612 1613 name = "FlowSpec traffic-rate extended community" 1614 fields_desc = [ 1615 ShortField("id", 0), 1616 IEEEFloatField("rate", 0) 1617 ] 1618 1619 1620class BGPPAExtCommTrafficAction(Packet): 1621 """ 1622 Packet handling the (FlowSpec) "traffic-action" extended community. 1623 References: RFC 5575 1624 """ 1625 1626 name = "FlowSpec traffic-action extended community" 1627 fields_desc = [ 1628 BitField("reserved", 0, 46), 1629 BitField("sample", 0, 1), 1630 BitField("terminal_action", 0, 1) 1631 ] 1632 1633 1634class BGPPAExtCommRedirectAS2Byte(Packet): 1635 """ 1636 Packet handling the (FlowSpec) "redirect AS-2byte" extended community 1637 (RFC 7674). 1638 References: RFC 7674 1639 """ 1640 1641 name = "FlowSpec redirect AS-2byte extended community" 1642 fields_desc = [ 1643 ShortField("asn", 0), 1644 IntField("value", 0) 1645 ] 1646 1647 1648class BGPPAExtCommRedirectIPv4(Packet): 1649 """ 1650 Packet handling the (FlowSpec) "redirect IPv4" extended community. 1651 (RFC 7674). 1652 References: RFC 7674 1653 """ 1654 1655 name = "FlowSpec redirect IPv4 extended community" 1656 fields_desc = [ 1657 IntField("ip_addr", 0), 1658 ShortField("value", 0) 1659 ] 1660 1661 1662class BGPPAExtCommRedirectAS4Byte(Packet): 1663 """ 1664 Packet handling the (FlowSpec) "redirect AS-4byte" extended community. 1665 (RFC 7674). 1666 References: RFC 7674 1667 """ 1668 1669 name = "FlowSpec redirect AS-4byte extended community" 1670 fields_desc = [ 1671 IntField("asn", 0), 1672 ShortField("value", 0) 1673 ] 1674 1675 1676class BGPPAExtCommTrafficMarking(Packet): 1677 """ 1678 Packet handling the (FlowSpec) "traffic-marking" extended community. 1679 References: RFC 5575 1680 """ 1681 1682 name = "FlowSpec traffic-marking extended community" 1683 fields_desc = [ 1684 BitEnumField("dscp", 48, 48, _ext_comm_traffic_action_fields) 1685 ] 1686 1687 1688_ext_high_low_dict = { 1689 BGPPAExtCommTwoOctetASSpecific: (0x00, 0x00), 1690 BGPPAExtCommIPv4AddressSpecific: (0x01, 0x00), 1691 BGPPAExtCommFourOctetASSpecific: (0x02, 0x00), 1692 BGPPAExtCommOpaque: (0x03, 0x00), 1693 BGPPAExtCommTrafficRate: (0x80, 0x06), 1694 BGPPAExtCommTrafficAction: (0x80, 0x07), 1695 BGPPAExtCommRedirectAS2Byte: (0x80, 0x08), 1696 BGPPAExtCommTrafficMarking: (0x80, 0x09), 1697 BGPPAExtCommRedirectIPv4: (0x81, 0x08), 1698 BGPPAExtCommRedirectAS4Byte: (0x82, 0x08), 1699} 1700 1701 1702class _ExtCommValuePacketField(PacketField): 1703 """ 1704 PacketField handling Extended Communities "value parts". 1705 """ 1706 1707 __slots__ = ["type_from"] 1708 1709 def __init__(self, name, default, cls, type_from=(0, 0)): 1710 PacketField.__init__(self, name, default, cls) 1711 self.type_from = type_from 1712 1713 def m2i(self, pkt, m): 1714 ret = None 1715 type_high, type_low = self.type_from(pkt) 1716 1717 if type_high == 0x00 or type_high == 0x40: 1718 # Two-Octet AS Specific Extended Community 1719 ret = BGPPAExtCommTwoOctetASSpecific(m) 1720 1721 elif type_high == 0x01 or type_high == 0x41: 1722 # IPv4 Address Specific 1723 ret = BGPPAExtCommIPv4AddressSpecific(m) 1724 1725 elif type_high == 0x02 or type_high == 0x42: 1726 # Four-octet AS Specific Extended Community 1727 ret = BGPPAExtCommFourOctetASSpecific(m) 1728 1729 elif type_high == 0x03 or type_high == 0x43: 1730 # Opaque 1731 ret = BGPPAExtCommOpaque(m) 1732 1733 elif type_high == 0x80: 1734 # FlowSpec 1735 if type_low == 0x06: 1736 ret = BGPPAExtCommTrafficRate(m) 1737 elif type_low == 0x07: 1738 ret = BGPPAExtCommTrafficAction(m) 1739 elif type_low == 0x08: 1740 ret = BGPPAExtCommRedirectAS2Byte(m) 1741 elif type_low == 0x09: 1742 ret = BGPPAExtCommTrafficMarking(m) 1743 1744 elif type_high == 0x81: 1745 # FlowSpec 1746 if type_low == 0x08: 1747 ret = BGPPAExtCommRedirectIPv4(m) 1748 1749 elif type_high == 0x82: 1750 # FlowSpec 1751 if type_low == 0x08: 1752 ret = BGPPAExtCommRedirectAS4Byte(m) 1753 1754 else: 1755 ret = conf.raw_layer(m) 1756 1757 return ret 1758 1759 1760class BGPPAIPv6AddressSpecificExtComm(Packet): 1761 """ 1762 Provides an implementation of the IPv6 Address Specific Extended 1763 Community attribute. This attribute is not defined using the existing 1764 BGP Extended Community attribute (see the RFC 5701 excerpt below). 1765 References: RFC 5701 1766 """ 1767 1768 name = "IPv6 Address Specific Extended Community" 1769 fields_desc = [ 1770 IP6Field("global_administrator", "::"), ShortField("local_administrator", 0)] # noqa: E501 1771 1772 1773def _get_ext_comm_subtype(type_high): 1774 """ 1775 Returns a ByteEnumField with the right sub-types dict for a given community. # noqa: E501 1776 http://www.iana.org/assignments/bgp-extended-communities/bgp-extended-communities.xhtml 1777 """ 1778 1779 return _ext_comm_subtypes_classes.get(type_high, {}) 1780 1781 1782class _TypeLowField(ByteField): 1783 """ 1784 Field used to retrieve "dynamically" the right sub-type dict. 1785 """ 1786 1787 __slots__ = ["enum_from"] 1788 1789 def __init__(self, name, default, enum_from=None): 1790 ByteField.__init__(self, name=name, default=default) 1791 self.enum_from = enum_from 1792 1793 def i2repr(self, pkt, i): 1794 enum = self.enum_from(pkt) 1795 return enum.get(i, i) 1796 1797 1798class BGPPAExtCommunity(Packet): 1799 """ 1800 Provides an implementation of the Extended Communities attribute. 1801 References: RFC 4360 1802 """ 1803 1804 name = "EXTENDED_COMMUNITY" 1805 fields_desc = [ 1806 ByteEnumField("type_high", 0, _ext_comm_types), 1807 _TypeLowField( 1808 "type_low", 1809 None, 1810 enum_from=lambda x: _get_ext_comm_subtype(x.type_high) 1811 ), 1812 _ExtCommValuePacketField( 1813 "value", 1814 None, 1815 Packet, 1816 type_from=lambda x: (x.type_high, x.type_low) 1817 ) 1818 ] 1819 1820 def post_build(self, p, pay): 1821 if self.value is None: 1822 p = p[:2] 1823 if self.type_low is None and self.value is not None: 1824 high, low = _ext_high_low_dict.get(self.value.__class__, (0x00, 0x00)) # noqa: E501 1825 p = chb(high) + chb(low) + p[2:] 1826 return p + pay 1827 1828 1829class _ExtCommsPacketListField(PacketListField): 1830 """ 1831 PacketListField handling a list of extended communities. 1832 """ 1833 1834 def getfield(self, pkt, s): 1835 lst = [] 1836 length = len(s) 1837 remain = s[:length] 1838 1839 while remain: 1840 current = remain[:8] 1841 remain = remain[8:] 1842 packet = self.m2i(pkt, current) 1843 lst.append(packet) 1844 1845 return remain, lst 1846 1847 1848class BGPPAExtComms(Packet): 1849 """ 1850 Packet handling the multiple extended communities. 1851 """ 1852 1853 name = "EXTENDED_COMMUNITIES" 1854 fields_desc = [ 1855 _ExtCommsPacketListField( 1856 "extended_communities", 1857 [], 1858 BGPPAExtCommunity 1859 ) 1860 ] 1861 1862 1863class MPReachNLRIPacketListField(PacketListField): 1864 """ 1865 PacketListField handling the AFI specific part (except for the length of 1866 Next Hop Network Address field, which is not AFI specific) of the 1867 MP_REACH_NLRI attribute. 1868 """ 1869 1870 def getfield(self, pkt, s): 1871 lst = [] 1872 remain = s 1873 1874 # IPv6 1875 if pkt.afi == 2: 1876 if pkt.safi == 1: 1877 # BGPNLRI_IPv6 1878 while remain: 1879 mask = orb(remain[0]) 1880 length_in_bytes = (mask + 7) // 8 1881 current = remain[:length_in_bytes + 1] 1882 remain = remain[length_in_bytes + 1:] 1883 prefix = self.m2i(pkt, current) 1884 lst.append(prefix) 1885 1886 return remain, lst 1887 1888 1889class BGPPAMPReachNLRI(Packet): 1890 """ 1891 Packet handling the MP_REACH_NLRI attribute value, for non IPv6 1892 AFI. 1893 References: RFC 4760 1894 """ 1895 1896 name = "MP_REACH_NLRI" 1897 fields_desc = [ 1898 ShortEnumField("afi", 0, address_family_identifiers), 1899 ByteEnumField("safi", 0, subsequent_afis), 1900 ByteField("nh_addr_len", 0), 1901 ConditionalField(IPField("nh_v4_addr", "0.0.0.0"), 1902 lambda x: x.afi == 1 and x.nh_addr_len == 4), 1903 ConditionalField(IP6Field("nh_v6_addr", "::"), 1904 lambda x: x.afi == 2 and x.nh_addr_len == 16), 1905 ConditionalField(IP6Field("nh_v6_global", "::"), 1906 lambda x: x.afi == 2 and x.nh_addr_len == 32), 1907 ConditionalField(IP6Field("nh_v6_link_local", "::"), 1908 lambda x: x.afi == 2 and x.nh_addr_len == 32), 1909 ByteField("reserved", 0), 1910 MPReachNLRIPacketListField("nlri", [], BGPNLRI_IPv6)] 1911 1912 def post_build(self, p, pay): 1913 if self.nlri is None: 1914 p = p[:3] 1915 1916 return p + pay 1917 1918 1919# 1920# MP_UNREACH_NLRI 1921# 1922 1923class BGPPAMPUnreachNLRI_IPv6(Packet): 1924 """ 1925 Packet handling the MP_UNREACH_NLRI attribute value, for IPv6 AFI. 1926 """ 1927 1928 name = "MP_UNREACH_NLRI (IPv6 NLRI)" 1929 fields_desc = [BGPNLRIPacketListField("withdrawn_routes", [], "IPv6")] 1930 1931 1932class MPUnreachNLRIPacketField(PacketField): 1933 """ 1934 PacketField handling the AFI specific part of the MP_UNREACH_NLRI 1935 attribute. 1936 """ 1937 1938 def m2i(self, pkt, m): 1939 ret = None 1940 1941 if pkt.afi == 2: 1942 ret = BGPPAMPUnreachNLRI_IPv6(m) 1943 else: 1944 ret = conf.raw_layer(m) 1945 1946 return ret 1947 1948 1949class BGPPAMPUnreachNLRI(Packet): 1950 """ 1951 Packet handling the MP_UNREACH_NLRI attribute value, for non IPv6 1952 AFI. 1953 References: RFC 4760 1954 """ 1955 1956 name = "MP_UNREACH_NLRI" 1957 fields_desc = [ShortEnumField("afi", 0, address_family_identifiers), 1958 ByteEnumField("safi", 0, subsequent_afis), 1959 MPUnreachNLRIPacketField("afi_safi_specific", None, Packet)] 1960 1961 def post_build(self, p, pay): 1962 if self.afi_safi_specific is None: 1963 p = p[:3] 1964 1965 return p + pay 1966 1967 1968# 1969# AS4_PATH 1970# 1971 1972class BGPPAAS4Path(Packet): 1973 """ 1974 Provides an implementation of the AS4_PATH attribute "value part". 1975 References: RFC 4893 1976 """ 1977 1978 name = "AS4_PATH" 1979 fields_desc = [ 1980 ByteEnumField( 1981 "segment_type", 1982 2, 1983 {1: "AS_SET", 2: "AS_SEQUENCE"} 1984 ), 1985 ByteField("segment_length", None), 1986 FieldListField("segment_value", [], IntField("asn", 0)) 1987 ] 1988 1989 def post_build(self, p, pay): 1990 if self.segment_length is None: 1991 segment_len = len(self.segment_value) 1992 p = p[:1] + chb(segment_len) + p[2:] 1993 1994 return p + pay 1995 1996 1997# 1998# LARGE_COMMUNITY 1999# 2000 2001class BGPLargeCommunitySegment(Packet): 2002 """ 2003 Provides an implementation for LARGE_COMMUNITY segments 2004 which holds 3*4 bytes integers. 2005 """ 2006 2007 fields_desc = [ 2008 IntField("global_administrator", None), 2009 IntField("local_data_part1", None), 2010 IntField("local_data_part2", None) 2011 ] 2012 2013 2014class BGPPALargeCommunity(Packet): 2015 """ 2016 Provides an implementation of the LARGE_COMMUNITY attribute. 2017 References: RFC 8092, RFC 8195 2018 """ 2019 2020 name = "LARGE_COMMUNITY" 2021 fields_desc = [PacketListField("segments", [], BGPLargeCommunitySegment)] 2022 2023# 2024# AS4_AGGREGATOR 2025# 2026 2027 2028class BGPPAAS4Aggregator(Packet): 2029 """ 2030 Provides an implementation of the AS4_AGGREGATOR attribute 2031 "value part". 2032 References: RFC 4893 2033 """ 2034 2035 name = "AS4_AGGREGATOR " 2036 fields_desc = [IntField("aggregator_asn", 0), 2037 IPField("speaker_address", "0.0.0.0")] 2038 2039 2040_path_attr_objects = { 2041 0x01: "BGPPAOrigin", 2042 0x02: "BGPPAASPath", # if bgp_module_conf.use_2_bytes_asn, BGPPAAS4BytesPath otherwise # noqa: E501 2043 0x03: "BGPPANextHop", 2044 0x04: "BGPPAMultiExitDisc", 2045 0x05: "BGPPALocalPref", 2046 0x06: "BGPPAAtomicAggregate", 2047 0x07: "BGPPAAggregator", 2048 0x08: "BGPPACommunity", 2049 0x09: "BGPPAOriginatorID", 2050 0x0A: "BGPPAClusterList", 2051 0x0E: "BGPPAMPReachNLRI", 2052 0x0F: "BGPPAMPUnreachNLRI", 2053 0x10: "BGPPAExtComms", 2054 0x11: "BGPPAAS4Path", 2055 0x19: "BGPPAIPv6AddressSpecificExtComm", 2056 0x20: "BGPPALargeCommunity" 2057} 2058 2059 2060class _PathAttrPacketField(PacketField): 2061 """ 2062 PacketField handling path attribute value parts. 2063 """ 2064 2065 def m2i(self, pkt, m): 2066 ret = None 2067 type_code = pkt.type_code 2068 2069 # Reserved 2070 if type_code == 0 or type_code == 255: 2071 ret = conf.raw_layer(m) 2072 # Unassigned 2073 elif (type_code >= 33 and type_code <= 39) or\ 2074 (type_code >= 41 and type_code <= 127) or\ 2075 (type_code >= 129 and type_code <= 254): 2076 ret = conf.raw_layer(m) 2077 # Known path attributes 2078 else: 2079 if type_code == 0x02 and not bgp_module_conf.use_2_bytes_asn: 2080 ret = BGPPAAS4BytesPath(m) 2081 elif type_code == 0x20: 2082 ret = BGPPALargeCommunity(m) 2083 else: 2084 ret = _get_cls( 2085 _path_attr_objects.get(type_code, conf.raw_layer))(m) 2086 2087 return ret 2088 2089 2090class BGPPathAttr(Packet): 2091 """ 2092 Provides an implementation of the path attributes. 2093 References: RFC 4271 2094 """ 2095 2096 name = "BGPPathAttr" 2097 fields_desc = [ 2098 FlagsField("type_flags", 0x80, 8, [ 2099 "NA0", 2100 "NA1", 2101 "NA2", 2102 "NA3", 2103 "Extended-Length", 2104 "Partial", 2105 "Transitive", 2106 "Optional" 2107 ]), 2108 ByteEnumField("type_code", 0, path_attributes), 2109 ConditionalField( 2110 ShortField("attr_ext_len", None), 2111 lambda x: x.type_flags is not None and 2112 has_extended_length(x.type_flags) 2113 ), 2114 ConditionalField( 2115 ByteField("attr_len", None), 2116 lambda x: x.type_flags is not None and not 2117 has_extended_length(x.type_flags) 2118 ), 2119 _PathAttrPacketField("attribute", None, Packet) 2120 ] 2121 2122 def post_build(self, p, pay): 2123 flags_value = None 2124 length = None 2125 packet = None 2126 extended_length = False 2127 2128 # Set default flags value ? 2129 if self.type_flags is None: 2130 # Set the standard value, if it is exists in attributes_flags. 2131 if self.type_code in attributes_flags: 2132 flags_value = attributes_flags.get(self.type_code) 2133 2134 # Otherwise, set to optional, non-transitive. 2135 else: 2136 flags_value = 0x80 2137 2138 extended_length = has_extended_length(flags_value) 2139 else: 2140 extended_length = has_extended_length(self.type_flags) 2141 2142 # Set the flags 2143 if flags_value is None: 2144 packet = p[:2] 2145 else: 2146 packet = struct.pack("!B", flags_value) + p[1] 2147 2148 # Add the length 2149 if self.attr_len is None: 2150 if self.attribute is None: 2151 length = 0 2152 else: 2153 if extended_length: 2154 length = len(p) - 4 # Flags + Type + Length (2 bytes) 2155 else: 2156 length = len(p) - 3 # Flags + Type + Length (1 byte) 2157 2158 if length is None: 2159 if extended_length: 2160 packet = packet + p[2:4] 2161 else: 2162 packet = packet + p[2] 2163 else: 2164 if extended_length: 2165 packet = packet + struct.pack("!H", length) 2166 else: 2167 packet = packet + struct.pack("!B", length) 2168 2169 # Append the rest of the message 2170 if extended_length: 2171 if self.attribute is not None: 2172 packet = packet + p[4:] 2173 else: 2174 if self.attribute is not None: 2175 packet = packet + p[3:] 2176 2177 return packet + pay 2178 2179 2180# 2181# UPDATE 2182# 2183 2184class BGPUpdate(BGP): 2185 """ 2186 UPDATE messages allow peers to exchange routes. 2187 References: RFC 4271 2188 """ 2189 2190 name = "UPDATE" 2191 fields_desc = [ 2192 FieldLenField( 2193 "withdrawn_routes_len", 2194 None, 2195 length_of="withdrawn_routes", 2196 fmt="!H" 2197 ), 2198 BGPNLRIPacketListField( 2199 "withdrawn_routes", 2200 [], 2201 "IPv4", 2202 length_from=lambda p: p.withdrawn_routes_len 2203 ), 2204 FieldLenField( 2205 "path_attr_len", 2206 None, 2207 length_of="path_attr", 2208 fmt="!H" 2209 ), 2210 BGPPathAttrPacketListField( 2211 "path_attr", 2212 [], 2213 BGPPathAttr, 2214 length_from=lambda p: p.path_attr_len 2215 ), 2216 BGPNLRIPacketListField("nlri", [], "IPv4") 2217 ] 2218 2219 def post_build(self, p, pay): 2220 subpacklen = lambda p: len(p) 2221 packet = "" 2222 if self.withdrawn_routes_len is None: 2223 wl = sum(map(subpacklen, self.withdrawn_routes)) 2224 packet = p[:0] + struct.pack("!H", wl) + p[2:] 2225 else: 2226 wl = self.withdrawn_routes_len 2227 if self.path_attr_len is None: 2228 length = sum(map(subpacklen, self.path_attr)) 2229 packet = p[:2 + wl] + struct.pack("!H", length) + p[4 + wl:] 2230 2231 return packet + pay 2232 2233 2234# 2235# NOTIFICATION 2236# 2237 2238# 2239# RFC 4271, RFC 7313 2240# http://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-parameters-3 2241# 2242_error_codes = { 2243 0x01: "Message Header Error", 2244 0x02: "OPEN Message Error", 2245 0x03: "UPDATE Message Error", 2246 0x04: "Hold Timer Expired", 2247 0x05: "Finite State Machine Error", 2248 0x06: "Cease", 2249 0x07: "ROUTE-REFRESH Message Error", # RFC 7313 2250} 2251 2252# 2253# http://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-parameters-4 2254# 2255_error_subcodes = { 2256 # Reserved 2257 0: {}, 2258 2259 # Header (RFC 4271) 2260 1: 2261 { 2262 0: "Unspecific", 2263 1: "Connection Not Synchronized", 2264 2: "Bad Message Length", 2265 3: "Bad Message Type" 2266 }, 2267 2268 # OPEN (RFC 4271, RFC 5492) 2269 2: 2270 { 2271 0: "Reserved", 2272 1: "Unsupported Version Number", 2273 2: "Bad Peer AS", 2274 3: "Bad BGP Identifier", 2275 4: "Unsupported Optional Parameter", 2276 5: "Authentication Failure - Deprecated (RFC 4271)", 2277 6: "Unacceptable Hold Time", 2278 7: "Unsupported Capability" 2279 }, 2280 2281 # UPDATE (RFC 4271) 2282 3: 2283 { 2284 0: "Reserved", 2285 1: "Malformed Attribute List", 2286 2: "Unrecognized Well-known Attribute", 2287 3: "Missing Well-known Attribute", 2288 4: "Attribute Flags Error", 2289 5: "Attribute Length Error", 2290 6: "Invalid ORIGIN Attribute", 2291 7: "AS Routing Loop - Deprecated (RFC 4271)", 2292 8: "Invalid NEXT_HOP Attribute", 2293 9: "Optional Attribute Error", 2294 10: "Invalid Network Field", 2295 11: "Malformed AS_PATH" 2296 }, 2297 2298 # Hold Timer Expired 2299 4: {}, 2300 2301 # Finite State Machine Error (RFC 6608) 2302 5: 2303 { 2304 0: "Unspecified Error", 2305 1: "Receive Unexpected Message in OpenSent State", 2306 2: "Receive Unexpected Message in OpenConfirm State", 2307 3: "Receive Unexpected Message in Established State" 2308 }, 2309 2310 # Cease (RFC 4486) 2311 6: 2312 { 2313 0: "Unspecified Error", 2314 1: "Maximum Number of Prefixes Reached", 2315 2: "Administrative Shutdown", 2316 3: "Peer De-configured", 2317 4: "Administrative Reset", 2318 5: "Connection Rejected", 2319 6: "Other Configuration Change", 2320 7: "Connection Collision Resolution", 2321 8: "Out of Resources", 2322 }, 2323 2324 # ROUTE-REFRESH (RFC 7313) 2325 7: 2326 { 2327 0: "Reserved", 2328 1: "Invalid Message Length" 2329 }, 2330} 2331 2332 2333class BGPNotification(BGP): 2334 """ 2335 NOTIFICATION messages end a BGP session. 2336 References: RFC 4271 2337 """ 2338 2339 name = "NOTIFICATION" 2340 fields_desc = [ 2341 ByteEnumField("error_code", 0, _error_codes), 2342 MultiEnumField( 2343 "error_subcode", 2344 0, 2345 _error_subcodes, 2346 depends_on=lambda p: p.error_code, 2347 fmt="B" 2348 ), 2349 StrField(name="data", default=None) 2350 ] 2351 2352 2353# 2354# ROUTE_REFRESH 2355# 2356 2357_orf_when_to_refresh = { 2358 0x01: "IMMEDIATE", 2359 0x02: "DEFER" 2360} 2361 2362 2363_orf_actions = { 2364 0: "ADD", 2365 1: "REMOVE", 2366 2: "REMOVE-ALL" 2367} 2368 2369 2370_orf_match = { 2371 0: "PERMIT", 2372 1: "DENY" 2373} 2374 2375 2376_orf_entry_afi = 1 2377_orf_entry_safi = 1 2378 2379 2380def _update_orf_afi_safi(afi, safi): 2381 """ 2382 Helper function that sets the afi / safi values 2383 of ORP entries. 2384 """ 2385 2386 global _orf_entry_afi 2387 global _orf_entry_safi 2388 2389 _orf_entry_afi = afi 2390 _orf_entry_safi = safi 2391 2392 2393class BGPORFEntry(Packet): 2394 """ 2395 Provides an implementation of an ORF entry. 2396 References: RFC 5291 2397 """ 2398 __slots__ = ["afi", "safi"] 2399 name = "ORF entry" 2400 fields_desc = [ 2401 BitEnumField("action", 0, 2, _orf_actions), 2402 BitEnumField("match", 0, 1, _orf_match), 2403 BitField("reserved", 0, 5), 2404 StrField("value", "") 2405 ] 2406 2407 def __init__(self, *args, **kwargs): 2408 self.afi = kwargs.pop("afi", 1) 2409 self.safi = kwargs.pop("safi", 1) 2410 super(BGPORFEntry, self).__init__(*args, **kwargs) 2411 2412 2413class _ORFNLRIPacketField(PacketField): 2414 """ 2415 PacketField handling the ORF NLRI. 2416 """ 2417 2418 def m2i(self, pkt, m): 2419 ret = None 2420 2421 if pkt.afi == 1: 2422 # IPv4 2423 ret = BGPNLRI_IPv4(m) 2424 2425 elif pkt.afi == 2: 2426 # IPv6 2427 ret = BGPNLRI_IPv6(m) 2428 2429 else: 2430 ret = conf.raw_layer(m) 2431 2432 return ret 2433 2434 2435class BGPORFAddressPrefix(BGPORFEntry): 2436 """ 2437 Provides an implementation of the Address Prefix ORF (RFC 5292). 2438 """ 2439 name = "Address Prefix ORF" 2440 fields_desc = [ 2441 BitEnumField("action", 0, 2, _orf_actions), 2442 BitEnumField("match", 0, 1, _orf_match), 2443 BitField("reserved", 0, 5), 2444 IntField("sequence", 0), 2445 ByteField("min_len", 0), 2446 ByteField("max_len", 0), 2447 _ORFNLRIPacketField("prefix", "", Packet), 2448 ] 2449 2450 2451class BGPORFCoveringPrefix(BGPORFEntry): 2452 """ 2453 Provides an implementation of the CP-ORF (RFC 7543). 2454 """ 2455 name = "CP-ORF" 2456 fields_desc = [ 2457 BitEnumField("action", 0, 2, _orf_actions), 2458 BitEnumField("match", 0, 1, _orf_match), 2459 BitField("reserved", 0, 5), 2460 IntField("sequence", 0), 2461 ByteField("min_len", 0), 2462 ByteField("max_len", 0), 2463 LongField("rt", 0), 2464 LongField("import_rt", 0), 2465 ByteField("route_type", 0), 2466 PacketField("host_addr", None, Packet) 2467 ] 2468 2469 2470class BGPORFEntryPacketListField(PacketListField): 2471 """ 2472 PacketListField handling the ORF entries. 2473 """ 2474 2475 def m2i(self, pkt, m): 2476 ret = None 2477 2478 if isinstance(pkt.underlayer, BGPRouteRefresh): 2479 afi = pkt.underlayer.afi 2480 safi = pkt.underlayer.safi 2481 else: 2482 afi = 1 2483 safi = 1 2484 2485 # Cisco also uses 128 2486 if pkt.orf_type == 64 or pkt.orf_type == 128: 2487 ret = BGPORFAddressPrefix(m, afi=afi, safi=safi) 2488 2489 elif pkt.orf_type == 65: 2490 ret = BGPORFCoveringPrefix(m, afi=afi, safi=safi) 2491 2492 else: 2493 ret = conf.raw_layer(m) 2494 2495 return ret 2496 2497 def getfield(self, pkt, s): 2498 lst = [] 2499 length = 0 2500 ret = b"" 2501 if self.length_from is not None: 2502 length = self.length_from(pkt) 2503 remain = s 2504 if length <= 0: 2505 return s, [] 2506 if length is not None: 2507 remain, ret = s[:length], s[length:] 2508 2509 while remain: 2510 orf_len = length 2511 2512 # Get value length, depending on the ORF type 2513 if pkt.orf_type == 64 or pkt.orf_type == 128: 2514 # Address Prefix ORF 2515 # Get the length, in bits, of the prefix 2516 prefix_len = _bits_to_bytes_len( 2517 orb(remain[6]) 2518 ) 2519 # flags (1 byte) + sequence (4 bytes) + min_len (1 byte) + 2520 # max_len (1 byte) + mask_len (1 byte) + prefix_len 2521 orf_len = 8 + prefix_len 2522 2523 elif pkt.orf_type == 65: 2524 # Covering Prefix ORF 2525 2526 if pkt.afi == 1: 2527 # IPv4 2528 # sequence (4 bytes) + min_len (1 byte) + max_len (1 byte) + # noqa: E501 2529 # rt (8 bytes) + import_rt (8 bytes) + route_type (1 byte) 2530 orf_len = 23 + 4 2531 2532 elif pkt.afi == 2: 2533 # IPv6 2534 # sequence (4 bytes) + min_len (1 byte) + max_len (1 byte) + # noqa: E501 2535 # rt (8 bytes) + import_rt (8 bytes) + route_type (1 byte) 2536 orf_len = 23 + 16 2537 2538 elif pkt.afi == 25: 2539 # sequence (4 bytes) + min_len (1 byte) + max_len (1 byte) + # noqa: E501 2540 # rt (8 bytes) + import_rt (8 bytes) 2541 route_type = orb(remain[22]) 2542 2543 if route_type == 2: 2544 # MAC / IP Advertisement Route 2545 orf_len = 23 + 6 2546 2547 else: 2548 orf_len = 23 2549 2550 current = remain[:orf_len] 2551 remain = remain[orf_len:] 2552 packet = self.m2i(pkt, current) 2553 lst.append(packet) 2554 2555 return remain + ret, lst 2556 2557 2558class BGPORF(Packet): 2559 """ 2560 Provides an implementation of ORFs carried in the RR message. 2561 References: RFC 5291 2562 """ 2563 2564 name = "ORF" 2565 fields_desc = [ 2566 ByteEnumField("when_to_refresh", 0, _orf_when_to_refresh), 2567 ByteEnumField("orf_type", 0, _orf_types), 2568 FieldLenField("orf_len", None, length_of="entries", fmt="!H"), 2569 BGPORFEntryPacketListField( 2570 "entries", 2571 [], 2572 Packet, 2573 length_from=lambda p: p.orf_len, 2574 ) 2575 ] 2576 2577 2578# RFC 7313 2579# http://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#route-refresh-subcodes 2580rr_message_subtypes = { 2581 0: "Route-Refresh", 2582 1: "BoRR", 2583 2: "EoRR", 2584 255: "Reserved" 2585} 2586 2587 2588class BGPRouteRefresh(BGP): 2589 """ 2590 Provides an implementation of the ROUTE-REFRESH message. 2591 References: RFC 2918, RFC 7313 2592 """ 2593 2594 name = "ROUTE-REFRESH" 2595 fields_desc = [ 2596 ShortEnumField("afi", 1, address_family_identifiers), 2597 ByteEnumField("subtype", 0, rr_message_subtypes), 2598 ByteEnumField("safi", 1, subsequent_afis), 2599 ConditionalField( 2600 PacketField('orf_data', "", BGPORF), 2601 lambda p: ( 2602 (p.underlayer and p.underlayer.len or 24) > 23 2603 ) 2604 ) 2605 ] 2606 2607 2608# 2609# Layer bindings 2610# 2611 2612bind_layers(TCP, BGP, dport=179) 2613bind_layers(TCP, BGP, sport=179) 2614bind_layers(BGPHeader, BGPOpen, {"type": 1}) 2615bind_layers(BGPHeader, BGPUpdate, {"type": 2}) 2616bind_layers(BGPHeader, BGPNotification, {"type": 3}) 2617bind_layers(BGPHeader, BGPKeepAlive, {"type": 4}) 2618bind_layers(BGPHeader, BGPRouteRefresh, {"type": 5}) 2619 2620# When loading the module, display the current module configuration. 2621log_runtime.warning( 2622 "[bgp.py] use_2_bytes_asn: %s", bgp_module_conf.use_2_bytes_asn) 2623