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