Beispiel #1
0
    def unpack(cls, data, length=0, capability={}):
        """unpack bgp message based on its type
        """
        if len(data) < cls.HDR_LEN:
            # Every BGP message is at least 19 octets. The message is
            # uncompleted or the rest hasn't arrived yet.
            raise MessageUncompleted(
                message=
                "The message is uncompleted or the rest hasn't arrived yet.")

        # unpack the message header
        # check whether the first 16 octets of the data consist of the
        # BGP marker (all bits one)
        marker, length, msg_type = struct.unpack('!16sHB', data[:cls.HDR_LEN])
        if marker != cls.MARKER:
            raise BGPNotification(1, 1)

        if length < cls.HDR_LEN or length > cls.MAX_LEN:
            raise BGPNotification(1, 2)  # Bad Message Length

        if len(data) < length:
            raise MessageUncompleted()

        if msg_type not in cls.registered_message:
            raise BGPNotification(1, 3)  # Bad Message type

        msg_body = data[cls.HDR_LEN:length]
        klass = cls.registered_message[msg_type].unpack(data=msg_body,
                                                        length=length,
                                                        capability=capability)
        return klass
Beispiel #2
0
    def unpack(cls, data, length, capability):
        open_msg = dict()
        try:
            open_msg['version'], open_msg['asn'], open_msg['hold-time'] = struct.unpack('!BHH', data[:5])
        except:
            raise BGPNotification(1, 2)
        if open_msg['version'] != cls.VERSION:
            # BGP-4
            raise BGPNotification(2, 1)

        if open_msg['asn'] == 0:
            raise BGPNotification(2, 2)

        if isinstance(open_msg['asn'], float):
            tmp = str(open_msg['asn']).split('.')
            open_msg['asn'] = 65536 * (int(tmp[0])) + int(tmp[1])

        try:
            open_msg['bgp-id'] = IPAddress.unpack(data[5:9])
        except:
            raise BGPNotification(2, 3)

        opt_para_len = struct.unpack('!B', data[9:10])
        if opt_para_len:
            open_msg['capabilities'] = Capabilities.unpack(data[10:]).value
        return cls(value=open_msg, length=length)
Beispiel #3
0
 def unpack(cls, data, capability):
     """
     parse bgp local preference attribute
     :param data: raw binary data
     """
     if len(data) != 4:
         raise BGPNotification(3, 5)
     return cls(value=struct.unpack('!I', data)[0])
Beispiel #4
0
 def pack(cls, data, capability):
     try:
         return cls(value=data,
                    hex_value=b''.join([
                        IPAddress.pack(cluster_id) for cluster_id in data
                    ]))
     except:
         raise BGPNotification(3, 5)
Beispiel #5
0
 def unpack(cls, data, capability):
     """
     Parse originator id
     :param data:
     """
     if len(data) != 4:
         raise BGPNotification(3, 5)
     return cls(value=IPAddress.unpack(data))
Beispiel #6
0
 def unpack(cls, data, capability):
     """
     parse bgp ATOMIC_AGGREGATE attribute
     :param data:
     """
     if len(data) == 1:
         return cls(value=struct.unpack('!B', data)[0])
     else:
         raise BGPNotification(3, 5)
Beispiel #7
0
 def unpack(cls, data, capability):
     """
     Parse BGP nexthop.
     :param data: raw binary data
     """
     if len(data) % 4 == 0:
         next_hop = IPAddress.unpack(data)
         return cls(value=next_hop)
     else:
         raise BGPNotification(3, 5)
Beispiel #8
0
 def pack(cls, data, capability={}):
     """pack message data into binary data.
     """
     msg_type = data.get('type')
     if msg_type not in cls.registered_message:
         raise BGPNotification(1, 3)
     msg_body = cls.registered_message[msg_type].pack(data=data.get('msg'),
                                                      capability=capability)
     return cls(value=data.get('msg'),
                hex_value=cls.pack_header(msg_type, msg_body.hex_value))
Beispiel #9
0
 def unpack(cls, data, capability):
     """
     Parse culster list
     :param data
     """
     cluster_list = []
     if len(data) % 4 != 0:
         raise BGPNotification(3, 5)
     while data:
         cluster_list.append(IPAddress.unpack(data[0:4]))
         data = data[4:]
     return cls(value=cluster_list)
Beispiel #10
0
 def pack(cls, data, capability):
     try:
         if capability.get('asn4'):
             return cls(value=data,
                        hex_value=struct.pack('!I', data[0]) +
                        IPAddress.pack(data[1]))
         else:
             return cls(value=data,
                        hex_value=struct.pack('!H', data[0]) +
                        IPAddress.pack(data[1]))
     except:
         raise BGPNotification(3, 5)
Beispiel #11
0
 def pack(cls, data, capability):
     community_hex = b''
     for community in data:
         if community.upper() in WELL_KNOW_COMMUNITY_STR_2_INT:
             value = WELL_KNOW_COMMUNITY_STR_2_INT[community.upper()]
             community_hex += struct.pack('!I', value)
         else:
             try:
                 value = community.split(':')
                 value = int(value[0]) * 16 * 16 * 16 * 16 + int(value[1])
                 community_hex += struct.pack('!I', value)
             except Exception:
                 raise BGPNotification(3, 5)
     return cls(value=data, hex_value=community_hex)
Beispiel #12
0
    def unpack(cls, data, capability):

        """
        Parse AS PATH attributes.
        :param data: raw binary balue
        """
        # Loop over all path segments
        aspath = []
        while len(data) > 0:
            seg_type, length = struct.unpack('!BB', data[:2])
            if seg_type not in [cls.AS_SET, cls.AS_SEQUENCE, cls.AS_CONFED_SEQUENCE, cls.AS_CONFED_SET]:
                raise BGPNotification(3, 11)
            try:
                if capability.get('asn4'):
                    segment = list(struct.unpack('!%dI' % length, data[2:2 + length * 4]))
                    data = data[2 + length * 4:]

                else:
                    segment = list(struct.unpack('!%dH' % length, data[2:2 + length * 2]))
                    data = data[2 + length * 2:]
            except Exception:
                raise BGPNotification(3, 11)
            aspath.append((seg_type, segment))
        return cls(value=aspath)
Beispiel #13
0
    def unpack(cls, data, capability):
        """
        Parse Aggregator attributes.
        :param data: raw binary data
        """
        try:
            if not capability.get('asn4'):
                asn = struct.unpack('!H', data[:2])[0]
                aggregator = IPAddress.unpack(data[2:])
            else:
                asn = struct.unpack('!I', data[:4])[0]
                aggregator = IPAddress.unpack(data[4:])
        except Exception:
            raise BGPNotification(3, 5)

        return cls(value=[asn, aggregator])
Beispiel #14
0
    def unpack_nlri(data, addpath=False):
        """
        Parses an RFC4271 encoded blob of BGP prefixes into a list

        :param data: hex data
        :param addpath: support addpath or not
        :return: prefix_list
        """
        prefixes = []
        postfix = data
        while len(postfix) > 0:
            # for python2 and python3
            if addpath:
                path_id = struct.unpack('!I', postfix[0:4])[0]
                postfix = postfix[4:]
            if isinstance(postfix[0], int):
                prefix_len = postfix[0]
            else:
                prefix_len = ord(postfix[0:1])
            if prefix_len > 32:
                raise BGPNotification(3, 10, 'Prefix Length larger than 32')
            octet_len, remainder = int(prefix_len / 8), prefix_len % 8
            if remainder > 0:
                # prefix length doesn't fall on octet boundary
                octet_len += 1
            tmp = postfix[1:octet_len + 1]
            # for python2 and python3
            if isinstance(postfix[0], int):
                prefix_data = [i for i in tmp]
            else:
                prefix_data = [ord(i[0:1]) for i in tmp]
            # Zero the remaining bits in the last octet if it didn't fall
            # on an octet boundary
            if remainder > 0:
                prefix_data[-1] &= 255 << (8 - remainder)
            prefix_data = prefix_data + list(str(0)) * 4
            prefix = "%s.%s.%s.%s" % (tuple(
                prefix_data[0:4])) + '/' + str(prefix_len)
            if not addpath:
                prefixes.append(prefix)
            else:
                prefixes.append({'prefix': prefix, 'path_id': path_id})
            # Next prefix
            postfix = postfix[octet_len + 1:]

        return prefixes
Beispiel #15
0
 def unpack(cls, data, capability):
     community = []
     if data:
         try:
             length = len(data) / 2
             value_list = list(struct.unpack('!%dH' % length, data))
             while value_list:
                 value_type = value_list[
                     0] * 16 * 16 * 16 * 16 + value_list[1]
                 if value_type in WELL_KNOW_COMMUNITY_INT_2_STR:
                     community.append(
                         WELL_KNOW_COMMUNITY_INT_2_STR[value_type])
                 else:
                     community.append("%s:%s" %
                                      (value_list[0], value_list[1]))
                 value_list = value_list[2:]
         except Exception:
             raise BGPNotification(3, 5)
     return cls(value=community)
Beispiel #16
0
    def pack(cls, data, capability):
        as_path_raw = b''
        for segment in data:
            as_seg_raw = b''
            seg_type = segment[0]
            as_path_list = segment[1]
            if seg_type not in [cls.AS_SET, cls.AS_SEQUENCE, cls.AS_CONFED_SET, cls.AS_CONFED_SEQUENCE]:
                raise BGPNotification(3, 11)

            as_count = 0
            for asn in as_path_list:
                if capability.get('asn4'):
                    as_seg_raw += struct.pack('!I', asn)
                else:
                    as_seg_raw += struct.pack('!H', asn)
                as_count += 1
            as_path_raw += struct.pack('!B', seg_type) + struct.pack('!B', as_count) + as_seg_raw

        return cls(value=data, hex_value=as_path_raw)
Beispiel #17
0
 def pack(cls, data, capability):
     if data not in range(0, 65536):
         raise BGPNotification(3, 5)
     return cls(value=data, hex_value=struct.pack('!I', data))
Beispiel #18
0
    def unpack(cls, data, capability):

        if len(data) != 4:
            raise BGPNotification(3, 5)
        return cls(value=struct.unpack('!I', data)[0])
Beispiel #19
0
 def pack(cls, data, capability):
     try:
         return cls(data, IPAddress.pack(data))
     except:
         raise BGPNotification(3, 5)
Beispiel #20
0
    def unpack(cls, data, capability):

        origin = struct.unpack('!B', data)[0]
        if origin not in [cls.IGP, cls.EGP, cls.INCOMPLETE]:
            raise BGPNotification(3, 6)
        return cls(value=origin)
Beispiel #21
0
 def pack(cls, data, capability):
     if data not in [cls.IGP, cls.EGP, cls.INCOMPLETE]:
         raise BGPNotification(3, 6)
     return cls(data, struct.pack('!B', data))
Beispiel #22
0
 def unpack(cls, data, length, capability):
     if len(data) != 0:
         raise BGPNotification(1, 2)
     return cls(value=None, length=length + cls.HDR_LEN)