• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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