Example #1
0
    def __parse(self):
        self.parsed = True
        self.error = False 
        payload_pointer = 0

        self.afi = struct.unpack("!H", self.payload[:2])[0]
        self.safi = struct.unpack("!B", self.payload[2])[0] # @todo use this if wanted, atm its not neccesary
        self.next_hop_length = struct.unpack("!B", self.payload[3])[0]
        payload_pointer = 4

        if not self.next_hop_length == 0: #next_hop parsing
            try:
                if self.afi == 1: #IPv4
                    if not self.next_hop_length % 4 == 0:
                        self.error = True
                    else: 
                        for i in range(self.next_hop_length / 4):
                            self.next_hop.append( MPNextHop(self.payload[payload_pointer:payload_pointer+4], socket.AF_INET) )
                            payload_pointer += 4

                elif self.afi == 2: #IPv6
                    if not self.next_hop_length % 16 == 0:
                        self.error = True
                    else: 
                        for i in range(self.next_hop_length / 16):
                            self.next_hop.append( MPNextHop(self.payload[payload_pointer:payload_pointer+16], socket.AF_INET6) )
                            payload_pointer += 16

                else:
                    raise NotImplementedError
        
            except Exception as e: 
                self.error = True

        if not len(self.payload) == self.next_hop_length + 5: # afi + safi + hop_length + reserved = 5bytes
            payload_pointer += 1 #skip reservation byte
            try:
                if self.afi == 1: #IPv4
                    while payload_pointer < len(self.payload):
                        prefix_len = struct.unpack("!B", self.payload[payload_pointer])[0]
                        prefix_len_bytes = int(math.ceil(prefix_len / 8.0))
                        
                        self.nlri.append(BGPRoute.from_binary(self.payload[payload_pointer+1:payload_pointer+1+prefix_len_bytes], self.payload[payload_pointer]))

                        payload_pointer += prefix_len_bytes + 1
                        
                elif self.afi == 2: #IPv6
                    while payload_pointer < len(self.payload):
                        prefix_len = struct.unpack("!B", self.payload[payload_pointer])[0]
                        prefix_len_bytes = int(math.ceil(prefix_len / 8.0))
                        
                        self.nlri.append(BGPRoute.from_binary(self.payload[payload_pointer+1:payload_pointer+1+prefix_len_bytes], self.payload[payload_pointer], BGPStatics.IP6_CODE))

                        payload_pointer += prefix_len_bytes + 1
                    
                else:
                    raise NotImplementedError

            except Exception as e: 
                self.error = True
Example #2
0
    def apply(self, message):
        try:
            # NEXT_HOP and COMMUNITIES are attributes of a BGP UPDATE message
            if message.type is not BGPStatics.MESSAGE_TYPE_UPDATE:
                # Skip messages that are no UPDATE messages
                return None

            for attribute in message.path_attributes:
                # Skip attributes that are no NEXT_HOP attributes
                if attribute.type is BGPStatics.UPDATE_ATTRIBUTE_NEXT_HOP:
                    # Here we found the NEXT_HOP attribute - check for blackhole next_hop
                    for value in self.values:
                        if str(
                                BGPRoute.decimal_ip_to_string(
                                    attribute.next_hop)) == str(value):
                            # Match on NEXT_HOP attribute - Return message
                            return message

                # Alternatively check if well-known BGP community is set (RFC 7999)
                if attribute.type is BGPStatics.UPDATE_ATTRIBUTE_COMMUNITIES:

                    for community in attribute.communities:
                        if community.asn == 65535 and community.value == 666:
                            return message

            # Searched value was not found
            return None
        except Exception as e:
            # On error the filtering was not successful (due to wrong fields, etc.)
            return None
Example #3
0
 def json(self):
     return {
         "type": self.type,
         "type_string": BGPTranslation.path_attribute(self.type),
         "error": self.error,
         "next_hop": str(BGPRoute.decimal_ip_to_string(self.next_hop))
     }
Example #4
0
    def apply(self, message):
        try:
            # NEXT_HOP is a path attribute of BGP UPDATE message
            # Therefore we first need to make that we are currently handling an UPDATE message
            if message.type is not BGPStatics.MESSAGE_TYPE_UPDATE:
                # Skip messages that are no UPDATE messages
                return None

            for attribute in message.path_attributes:
                # Skip attributes that are no NEXT_HOP attributes
                if attribute.type is not BGPStatics.UPDATE_ATTRIBUTE_NEXT_HOP:
                    continue

                # Here we found the NEXT_HOP attribute - loop through allowed values
                for value in self.values:
                    if str(BGPRoute.decimal_ip_to_string(
                            attribute.next_hop)) == str(value):
                        # Match on NEXT_HOP attribute - Return message
                        return message

            # Searched value was not found
            return None
        except Exception as e:
            # On error the filtering was not successful (due to wrong fields, etc.)
            return None
Example #5
0
    def __parse(self):
        self.parsed = True
        self.error = False
        payload_pointer = 0

        self.afi = struct.unpack("!H", self.payload[:2])[0]
        self.safi = struct.unpack("!B", self.payload[2])[0]

        payload_pointer = 3

        try:
            if self.afi == 1:  #IPv4
                while payload_pointer < len(self.payload):
                    prefix_len = struct.unpack(
                        "!B", self.payload[payload_pointer])[0]
                    prefix_len_bytes = int(math.ceil(prefix_len / 8.0))

                    self.nlri.append(
                        BGPRoute.from_binary(
                            self.payload[payload_pointer + 1:payload_pointer +
                                         1 + prefix_len_bytes],
                            self.payload[payload_pointer]))

                    payload_pointer += prefix_len_bytes + 1

            elif self.afi == 2:  #IPv6
                while payload_pointer < len(self.payload):
                    prefix_len = struct.unpack(
                        "!B", self.payload[payload_pointer])[0]
                    prefix_len_bytes = int(math.ceil(prefix_len / 8.0))

                    self.nlri.append(
                        BGPRoute.from_binary(
                            self.payload[payload_pointer + 1:payload_pointer +
                                         1 + prefix_len_bytes],
                            self.payload[payload_pointer],
                            BGPStatics.IP6_CODE))

                    payload_pointer += prefix_len_bytes + 1

            else:
                raise NotImplementedError

        except Exception as e:
            self.error = True
Example #6
0
    def apply(self, message):
        # Example return:
        #
        # [BGPMessage UPDATE] - [123.123.123.123 -> 123.123.123.123]
        # |- IP: 123.123.123.123 -> 123.123.123.123
        # |- MAC: 11:11:11:11:11:11 -> 11:11:11:11:11
        # |- Unix Time: 1412416346.123245123
        # |
        # |- Withdrawn Routes Length: 0
        # |- Total Path Attribute Length: 55
        # |- Path Attributes
        # |--- ORIGIN: IGP
        # |--- AS_PATH: (9498 9430)
        # |--- NEXT_HOP: 80.81.194.250
        # |--- COMMUNITIES: 9498:1 9498:11 9498:91
        # |- NLRI
        # |--- 203.190.42.0/24
        ##

        # Initialize basic return string and PCAP information
        string = "[BGPMessage " + BGPTranslation.message_type(
            message.type) + "] - " + str(message.length) + " Bytes\n"
        string += self.prefix(0) + "MAC: " + message.pcap_information.get_mac(
        ).get_source_string(
            separated=True) + " -> " + message.pcap_information.get_mac(
            ).get_destination_string(separated=True) + "\n"
        string += self.prefix(0) + "IP: " + message.pcap_information.get_ip(
        ).get_source_string() + ":" + message.pcap_information.get_ports(
        ).get_source_string() + " -> " + message.pcap_information.get_ip(
        ).get_destination_string() + ":" + message.pcap_information.get_ports(
        ).get_destination_string() + "\n"
        string += self.prefix(
            0) + "Timestamp: " + message.pcap_information.get_timestmap_utc(
            ) + " (" + str(
                message.pcap_information.get_timestamp()[0]) + "." + str(
                    message.pcap_information.get_timestamp()[1]) + ")\n"

        # Display additional information
        if BGPStatics.MESSAGE_TYPE_KEEPALIVE == message.type:
            pass

        if BGPStatics.MESSAGE_TYPE_OPEN == message.type:
            # --- Divider for PCAP information
            string += self.prefix(-1) + "\n"

            string += self.prefix(0) + "Version: " + str(
                message.version) + "\n"
            string += self.prefix(0) + "My ASN: " + str(message.asn) + "\n"
            string += self.prefix(0) + "Hold Time: " + str(
                message.hold_time) + "\n"
            string += self.prefix(0) + "BGP Identifier: " + str(
                BGPRoute.decimal_ip_to_string(message.identifier)) + "\n"

            # --- Optional Parameters
            string += self.prefix(0) + "Optional Parameters Length: " + str(
                message.optional_parameter_length) + " Bytes" + "\n"

            # Process optional parameters
            if message.optional_parameter_length > 0:
                string += self.prefix(0) + "Optional Parameters:" + "\n"

                for parameter in message.optional_parameter:
                    if parameter.type == BGPStatics.OPEN_CAPABILITY:
                        string += self.prefix(
                            1) + "Parameter: Capability" + "\n"

                        # Process capabilities
                        for capability in parameter.capability_list:
                            if capability.type is not BGPStatics.CAPABILITY_UNKNOWN:
                                string += self.prefix(
                                    2) + BGPTranslation.capability(
                                        capability.type) + " (" + str(
                                            capability.type) + ")\n"
                            else:
                                string += self.prefix(2) + str(
                                    capability) + "\n"

                    elif parameter.type == BGPStatics.OPEN_AUTHENTICATION:
                        string += self.prefix(
                            1) + "Parameter: Authentication" + "\n"
                    elif parameter.type == BGPStatics.OPEN_RESERVED:
                        string += self.prefix(1) + "Parameter: Reserved" + "\n"

        if BGPStatics.MESSAGE_TYPE_UPDATE == message.type:
            # --- Divider for PCAP information
            string += self.prefix(-1) + "\n"

            # --- Update Message Sub-Type
            string += self.prefix(
                0
            ) + "Update Message Sub-Type: " + BGPTranslation.update_subtype(
                message.subtype) + "\n"

            # --- Lengths
            string += self.prefix(0) + "Withdrawn Routes Length: " + str(
                message.withdrawn_routes_length) + " Bytes\n"
            string += self.prefix(0) + "Total Path Attribute Length: " + str(
                message.path_attributes_length) + " Bytes\n"

            # --- NLRI
            if len(message.nlri) > 0:
                string += self.prefix(0) + "Prefix (NLRI):"
                if message.add_path:
                    string += " (AddPath)\n" + self.prefix(
                        0) + "Path Identifier: " + str(message.path_id)
                string += "\n"

                # Process NLRI
                for route in message.nlri:
                    string += self.prefix(1) + str(route) + "\n"

            # --- Path Attributes
            if message.path_attributes_length > 0:

                # Process path attributes
                for attribute in message.path_attributes:
                    string += self.prefix(0) + "Path Attributes:" + "\n"

                    if attribute.type == BGPStatics.UPDATE_ATTRIBUTE_EXTENDED_COMMUNITIES:
                        # Extended Communities must be displayed in another way than other attributes
                        string += self.prefix(
                            1) + BGPTranslation.path_attribute(
                                attribute.type) + ":\n"

                        for community in attribute.extended_communities:
                            string += self.prefix(2) + str(community) + "\n"
                    else:
                        # We got a "normal" path attribute
                        string += self.prefix(
                            1) + BGPTranslation.path_attribute(
                                attribute.type) + ": " + str(attribute) + "\n"

            # --- Withdrawn Routes
            if message.withdrawn_routes_length > 0:
                string += self.prefix(0) + "Withdrawn Routes:"
                if message.add_path:
                    string += " (AddPath)\n" + self.prefix(
                        0) + "Path Identifier: " + str(message.path_id)
                string += "\n"

                # Process withdrawn routes
                for route in message.withdrawn_routes:
                    string += self.prefix(1) + str(route) + "\n"

        if BGPStatics.MESSAGE_TYPE_NOTIFICATION == message.type:
            pass

        if BGPStatics.MESSAGE_TYPE_ROUTE_REFRESH == message.type:
            pass

        if BGPStatics.MESSAGE_TYPE_RESERVED == message.type:
            pass

        # Return assembled string plus final line break
        return string + "\n"
Example #7
0
    def __parse(self):
        self.parsed = True

        try:
            # Check last two bytes of byte payload - if they are set to zero we don't have any path attributes
            if struct.unpack("!H", self.payload[-2:])[0] == 0:
                self.path_attributes_length = 0

            # Unpack the length of withdrawn routes field and add 2 bytes to the current byte marker position
            self.withdrawn_routes_length = struct.unpack(
                "!H", self.payload[:2])[0]
            current_byte_position = 2

            # Start parsing withdrawn routes
            if self.withdrawn_routes_length is not 0:
                continue_loop = True

                # Loop through withdrawals
                while continue_loop:
                    # First of all we need to parse the length of the withdrawn prefix. Depending on the prefix length
                    # we can determine the length following prefix itself
                    prefix_length_bytes = self.payload[
                        current_byte_position:current_byte_position + 1]
                    prefix_length = struct.unpack("!B", prefix_length_bytes)[0]
                    current_byte_position += 1

                    if 0 <= prefix_length <= 8:
                        # Length of prefix field: 1 Byte
                        prefix_bytes = self.payload[
                            current_byte_position:current_byte_position + 1]
                        current_byte_position += 1

                    elif 9 <= prefix_length <= 16:
                        # Length of prefix field: 2 Bytes
                        prefix_bytes = self.payload[
                            current_byte_position:current_byte_position + 2]
                        current_byte_position += 2

                    elif 17 <= prefix_length <= 24:
                        # Length of prefix field: 3 Bytes
                        prefix_bytes = self.payload[
                            current_byte_position:current_byte_position + 3]
                        current_byte_position += 3

                    elif 25 <= prefix_length:
                        # Length of prefix field: 4 Bytes
                        prefix_bytes = self.payload[
                            current_byte_position:current_byte_position + 4]
                        current_byte_position += 4

                    else:
                        self.error = True
                        raise BGPWithdrawnPrefixError(
                            "can't match prefix length.")

                    # Add BGPRoute object with information about the withdrawn route to list
                    self.withdrawn_routes.append(
                        BGPRoute.from_binary(prefix_bytes,
                                             prefix_length_bytes))

                    # Check if we are at the end of the payload
                    if self.withdrawn_routes_length <= current_byte_position:
                        # If yes we need to stop the iteration
                        continue_loop = False

            # Second step: Continue with the path attributes
            if self.path_attributes_length is None:
                # First of all get the attributes length field and update the current byte position
                self.path_attributes_length = struct.unpack(
                    "!H",
                    self.payload[current_byte_position:current_byte_position +
                                 2])[0]
                current_byte_position += 2

            # Now we have a correct path_attributes_length stored. If this length is zero we don't need to do anything
            if self.path_attributes_length is not 0:
                continue_loop = True

                # Loop through path attributes
                while continue_loop:
                    # Now comes a tricky part of UPDATE message parsing. Each path attribute has a flag bitfield.
                    # One of those flags is called 'extended length'. If it's set to 1 the following attribute fields
                    # are 2 bytes long. But if it's set to zero it's just 1 byte long ...

                    # So first of all: Flag parsing!
                    attribute_flags = BGPUpdateFlags(
                        struct.unpack(
                            "!B", self.payload[
                                current_byte_position:current_byte_position +
                                1])[0])
                    current_byte_position += 1

                    if attribute_flags.length:
                        # We got an extended length flag
                        attribute_fields = struct.unpack(
                            "!BH", self.payload[
                                current_byte_position:current_byte_position +
                                3])
                        current_byte_position += 3
                    else:
                        # We got a normal length flag
                        attribute_fields = struct.unpack(
                            "!BB", self.payload[
                                current_byte_position:current_byte_position +
                                2])
                        current_byte_position += 2

                    # Finally assign the variables
                    attribute_type = attribute_fields[0]
                    attribute_length = attribute_fields[1]

                    # Now we are using the factory pattern again to determine
                    # which kind of attribute we have to add the list
                    self.path_attributes.append(
                        BGPPathAttribute.factory(
                            attribute_type, self.payload[
                                current_byte_position:current_byte_position +
                                attribute_length], attribute_flags))

                    # Add length of attribute to position pointer
                    current_byte_position += attribute_length

                    # Check if there are further path attributes to parse
                    if current_byte_position >= self.path_attributes_length:
                        continue_loop = False

            # Third step: NLRIs
            if len(self.payload) > (self.path_attributes_length + 4 +
                                    self.withdrawn_routes_length):

                continue_loop = True

                # The four bytes that get added to the attributes and routes length are the two two-byte fields
                # for path attribute length and withdrawn routes length
                current_byte_position = self.path_attributes_length + 4 + self.withdrawn_routes_length

                while continue_loop:
                    # First of all we have to check the prefix length as byte-length of the following
                    # prefix depends on its prefix length (This is a 1-byte-field)
                    prefix_length_bytes = self.payload[
                        current_byte_position:current_byte_position + 1]
                    prefix_length = struct.unpack("!B", prefix_length_bytes)[0]
                    current_byte_position += 1

                    if 0 <= prefix_length <= 8:
                        # Length of prefix field: 1 Byte
                        prefix_bytes = self.payload[
                            current_byte_position:current_byte_position + 1]
                        current_byte_position += 1
                    elif 9 <= prefix_length <= 16:
                        # Length of prefix field: 2 Bytes
                        prefix_bytes = self.payload[
                            current_byte_position:current_byte_position + 2]
                        current_byte_position += 2
                    elif 17 <= prefix_length <= 24:
                        # Length of prefix field: 3 Bytes
                        prefix_bytes = self.payload[
                            current_byte_position:current_byte_position + 3]
                        current_byte_position += 3
                    elif 25 <= prefix_length:
                        # Length of prefix field: 4 Bytes
                        prefix_bytes = self.payload[
                            current_byte_position:current_byte_position + 4]
                        current_byte_position += 4
                    else:
                        self.error = True
                        raise BGPWithdrawnPrefixError(
                            "can't match prefix length.")

                    try:
                        self.nlri.append(
                            BGPRoute.from_binary(prefix_bytes,
                                                 prefix_length_bytes))
                    except BGPError as e:
                        raise BGPNLRIError(
                            "can't append NLRI to message (error: " + str(e) +
                            ")")

                    if current_byte_position >= len(self.payload):
                        continue_loop = False

            # Determine sub-type for filtering
            # Using bit flags for easier assignment
            if len(self.nlri) > 0:
                self.subtype = (self.subtype | BGPStatics.UPDATE_TYPE_ANNOUNCE)

            if len(self.withdrawn_routes) > 0:
                self.subtype = (self.subtype
                                | BGPStatics.UPDATE_TYPE_WITHDRAWAL)

        except BGPWithdrawnPrefixError as p:
            self.error = True
            logging.info(p)
        except Exception as e:
            self.error = True

        self.error = False
Example #8
0
 def __str__(self):
     if self.parsed and not self.error:
         return str(BGPRoute.decimal_ip_to_string(self.next_hop))
     else:
         return None
Example #9
0
    def __parse(self):
        self.parsed = True

        try:
            # Unpack the length of withdrawn routes field and add 2 bytes to the current byte marker position
            self.withdrawn_routes_length = struct.unpack(
                "!H", self.payload[:2])[0]
            current_byte_position = 2

            # Start parsing withdrawn routes
            if self.withdrawn_routes_length is not 0:
                continue_loop = True

                # Loop through withdrawals
                while continue_loop:
                    # AddPath assumption? look for description in the method for NLRI parsing
                    if self.flags["addpath"].get_value(
                    ) == 0:  # No AddPath messages
                        pass

                    else:
                        pathId_length_bytes = self.payload[
                            current_byte_position:current_byte_position + 4]
                        pathId = struct.unpack("!I", pathId_length_bytes)[0]

                        if self.flags["addpath"].get_value(
                        ) == 1:  # Only AddPath
                            self.add_path = True
                            self.path_id = pathId
                            current_byte_position += 4

                        else:  # Try to find out (using metric)
                            if pathId < 65536:
                                self.add_path = True
                                self.path_id = pathId
                                current_byte_position += 4
                            #else: drop the Path Id, its likely that this is not an AddPath msg

                    # First of all we need to parse the length of the withdrawn prefix. Depending on the prefix length
                    # we can determine the length following prefix itself
                    prefix_length_bytes = self.payload[
                        current_byte_position:current_byte_position + 1]
                    prefix_length = struct.unpack("!B", prefix_length_bytes)[0]
                    current_byte_position += 1

                    if prefix_length == 0:
                        prefix_bytes = prefix_length_bytes
                    elif 0 < prefix_length <= 8:
                        # Length of prefix field: 1 Byte
                        prefix_bytes = self.payload[
                            current_byte_position:current_byte_position + 1]
                        current_byte_position += 1

                    elif 9 <= prefix_length <= 16:
                        # Length of prefix field: 2 Bytes
                        prefix_bytes = self.payload[
                            current_byte_position:current_byte_position + 2]
                        current_byte_position += 2

                    elif 17 <= prefix_length <= 24:
                        # Length of prefix field: 3 Bytes
                        prefix_bytes = self.payload[
                            current_byte_position:current_byte_position + 3]
                        current_byte_position += 3

                    elif 25 <= prefix_length:
                        # Length of prefix field: 4 Bytes
                        prefix_bytes = self.payload[
                            current_byte_position:current_byte_position + 4]
                        current_byte_position += 4

                    else:
                        self.error = True
                        raise BGPWithdrawnPrefixError(
                            "can't match prefix length.")

                    # Add BGPRoute object with information about the withdrawn route to list
                    self.withdrawn_routes.append(
                        BGPRoute.from_binary(prefix_bytes,
                                             prefix_length_bytes))

                    # Check if we are at the end of the payload
                    if self.withdrawn_routes_length <= current_byte_position:
                        # If yes we need to stop the iteration
                        continue_loop = False

            # Second step: Continue with the path attributes
            if self.path_attributes_length is None:
                # First of all get the attributes length field and update the current byte position
                self.path_attributes_length = struct.unpack(
                    "!H",
                    self.payload[current_byte_position:current_byte_position +
                                 2])[0]
                current_byte_position += 2

            # Now we have a correct path_attributes_length stored. If this length is zero we don't need to do anything
            if self.path_attributes_length is not 0:
                continue_loop = True

                # Loop through path attributes
                while continue_loop:
                    # Now comes a tricky part of UPDATE message parsing. Each path attribute has a flag bitfield.
                    # One of those flags is called 'extended length'. If it's set to 1 the following attribute fields
                    # are 2 bytes long. But if it's set to zero it's just 1 byte long ...

                    # So first of all: Flag parsing!
                    attribute_flags = BGPUpdateFlags(
                        struct.unpack(
                            "!B", self.payload[
                                current_byte_position:current_byte_position +
                                1])[0])
                    current_byte_position += 1

                    if attribute_flags.length:
                        # We got an extended length flag
                        attribute_fields = struct.unpack(
                            "!BH", self.payload[
                                current_byte_position:current_byte_position +
                                3])
                        current_byte_position += 3
                    else:
                        # We got a normal length flag
                        attribute_fields = struct.unpack(
                            "!BB", self.payload[
                                current_byte_position:current_byte_position +
                                2])
                        current_byte_position += 2

                    # Finally assign the variables
                    attribute_type = attribute_fields[0]
                    attribute_length = attribute_fields[1]

                    # Now we are using the factory pattern again to determine
                    # which kind of attribute we have to add the list
                    self.path_attributes.append(
                        BGPPathAttribute.factory(
                            attribute_type, self.payload[
                                current_byte_position:current_byte_position +
                                attribute_length], attribute_flags))

                    # Add length of attribute to position pointer
                    current_byte_position += attribute_length

                    # Check if there are further path attributes to parse
                    if current_byte_position >= self.path_attributes_length:
                        continue_loop = False

            # Third step: NLRIs
            if len(self.payload) > (self.path_attributes_length + 4 +
                                    self.withdrawn_routes_length):

                continue_loop = True

                # The four bytes that get added to the attributes and routes length are the two two-byte fields
                # for path attribute length and withdrawn routes length
                current_byte_position = self.path_attributes_length + 4 + self.withdrawn_routes_length

                while continue_loop:
                    """
                    The Following is a Fix for missing Add_Path feature.
                    Due to the lack of a definition for this case, we need depend on the users decision.
                    See RFC 7911 Chapter 6 p.5 (22.07.2020).

                    In most cases, the pathId is lower than 2**16. Also it is uncommon,
                    that one BGP UPDATE message contains the 0.0.0.0/0 prefix 2 times.
                    This leads to the following metric if the user sets the add_path_flag to 2.
                    """
                    # AddPath assumption?
                    if self.flags["addpath"].get_value(
                    ) == 0:  # No AddPath messages
                        pass

                    else:
                        pathId_length_bytes = self.payload[
                            current_byte_position:current_byte_position + 4]
                        pathId = struct.unpack("!I", pathId_length_bytes)[0]

                        if self.flags["addpath"].get_value(
                        ) == 1:  # Only AddPath
                            self.add_path = True
                            self.path_id = pathId
                            current_byte_position += 4

                        else:  # Try to find out (using metric)
                            if pathId < 65536:
                                self.add_path = True
                                self.path_id = pathId
                                current_byte_position += 4
                            #else: drop the Path Id, its likely that this is not an AddPath msg

                    # First of all we have to check the prefix length as byte-length of the following
                    # prefix depends on its prefix length (This is a 1-byte-field)
                    prefix_length_bytes = self.payload[
                        current_byte_position:current_byte_position + 1]
                    prefix_length = struct.unpack("!B", prefix_length_bytes)[0]
                    current_byte_position += 1

                    if prefix_length == 0:  #0.0.0.0/0
                        prefix_bytes = prefix_length_bytes
                    elif 0 <= prefix_length <= 8:
                        # Length of prefix field: 1 Byte
                        prefix_bytes = self.payload[
                            current_byte_position:current_byte_position + 1]
                        current_byte_position += 1
                    elif 9 <= prefix_length <= 16:
                        # Length of prefix field: 2 Bytes
                        prefix_bytes = self.payload[
                            current_byte_position:current_byte_position + 2]
                        current_byte_position += 2
                    elif 17 <= prefix_length <= 24:
                        # Length of prefix field: 3 Bytes
                        prefix_bytes = self.payload[
                            current_byte_position:current_byte_position + 3]
                        current_byte_position += 3
                    elif 25 <= prefix_length:
                        # Length of prefix field: 4 Bytes
                        prefix_bytes = self.payload[
                            current_byte_position:current_byte_position + 4]
                        current_byte_position += 4
                    else:
                        self.error = True
                        raise BGPWithdrawnPrefixError(
                            "can't match prefix length.")

                    try:
                        self.nlri.append(
                            BGPRoute.from_binary(prefix_bytes,
                                                 prefix_length_bytes))
                    except BGPError as e:
                        raise BGPNLRIError(
                            "can't append NLRI to message (error: " + str(e) +
                            ")")

                    if current_byte_position >= len(self.payload):
                        continue_loop = False

            # Determine sub-type for filtering
            # Using bit flags for easier assignment
            if len(self.nlri) > 0:
                self.subtype = (self.subtype | BGPStatics.UPDATE_TYPE_ANNOUNCE)

            if len(self.withdrawn_routes) > 0:
                self.subtype = (self.subtype
                                | BGPStatics.UPDATE_TYPE_WITHDRAWAL)

        except BGPWithdrawnPrefixError as p:
            self.error = True
            logging.info(p)
        except Exception as e:
            self.error = True

        self.error = False