def parse(self, value, asn4=False): """ Parse AS PATH attributes. :param asn4: 4 bytes asn or not :param value: raw binary balue """ # Loop over all path segments aspath = [] while len(value) > 0: seg_type, length = struct.unpack('!BB', value[:2]) if seg_type not in [ self.AS_SET, self.AS_SEQUENCE, self.AS_CONFED_SEQUENCE, self.AS_CONFED_SET ]: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_MALFORMED_ASPATH, data=value[0]) try: if asn4: segment = list( struct.unpack('!%dI' % length, value[2:2 + length * 4])) value = value[2 + length * 4:] else: segment = list( struct.unpack('!%dH' % length, value[2:2 + length * 2])) value = value[2 + length * 2:] except Exception: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data='') aspath.append((seg_type, segment)) return aspath
def parse(value): """ Parse originator id :param value: """ if len(value) > 4: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=value) try: return IPv4Address(int(binascii.b2a_hex(value[0:4]), 16)).__str__() except Exception: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=value)
def parse(value): """ Parse culster list :param value """ cluster_list = [] if len(value) % 4 != 0: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=repr(value)) try: while value: cluster_list.append( IPv4Address(struct.unpack('!I', value[0:4])[0]).__str__()) value = value[4:] except Exception: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=repr(value)) return cluster_list
def parse(value): """ parse bgp ATOMIC_AGGREGATE attribute :param value: """ if not value: return value else: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_OPTIONAL_ATTR, data=value)
def parse(value): """ parse BGP med attributes :param value: raw binary value """ try: return struct.unpack('!I', value)[0] except: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=value)
def parse(message): """ parse notification message :param message: input raw binary message data """ try: error, suberror = struct.unpack('!BB', message[:2]) data = message[2:] except: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_HDR_BAD_MSG_LEN, data=repr(message)) return error, suberror, data
def construct(self, value, flags=None): """ construct a origin attribute """ if value not in [self.IGP, self.EGP, self.INCOMPLETE]: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_INVALID_ORIGIN, data='') length = 1 if not flags: flags = self.FLAG return struct.pack('!B', flags) + struct.pack('!B', self.ID) \ + struct.pack('!B', length) + struct.pack('!B', value)
def construct(self, value, flags=None): """ encode BGP nexthop attribute. """ try: ipv4_addr = IPv4Address(value) except: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_INVALID_NEXTHOP, data=value) ip_addr_raw = ipv4_addr.packed if not flags: flags = self.FLAG return struct.pack('!B', flags) + struct.pack('!B', self.ID) \ + struct.pack('!B', len(ip_addr_raw)) + ip_addr_raw
def parse(value): """ Parse BGP nexthop. :param value: raw binary value """ next_hop = '0.0.0.0' if len(value) % 4 == 0: while value: try: next_hop = IPv4Address( int(binascii.b2a_hex(value[0:4]), 16)).__str__() except Exception: # Error process raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_INVALID_NEXTHOP, data=value[0:4]) value = value[4:] else: # Error process raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=value) return next_hop
def construct(self, value, flags=None): """ encode BGP med attributes :param value: :param flags: bgp attribute flags """ if not flags: flags = self.FLAG try: return struct.pack('!B', flags) + struct.pack('!B', self.ID) \ + struct.pack('!B', 4) + struct.pack('!I', value) except Exception: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data='')
def construct(self, value, flags=None): """ construct a ORIGINATOR_ID path attribute :param value: :param flags: """ if not flags: flags = self.FLAG try: return struct.pack('!B', flags) + struct.pack('!B', self.ID) \ + struct.pack('!B', 4) + IPv4Address(value).packed except Exception: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=value)
def construct(self, value, flags=None): """construct a ATOMIC_AGGREGATE path attribute :param value: :param flags: """ if not flags: flags = self.FLAG if value: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_OPTIONAL_ATTR, data='') else: value = 0 return struct.pack('!B', flags) + struct.pack('!B', self.ID) \ + struct.pack('!B', value)
def parse(self, value): """ Error process: (1) the falgs of the ORIGIN attribute must be "well-know,transitive" (2) If the ORIGIN attribute has an undefined value, then the Error Sub-code MUST be set to Invalid Origin Attribute. The Data field MUST contain the unrecognized attribute (type,length, and vlaue) :param value: raw binary value """ orgin = struct.unpack('!B', value)[0] if orgin not in [self.IGP, self.EGP, self.INCOMPLETE]: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_INVALID_ORIGIN, data=value) return orgin
def construct(self, value, flags=None, asn4=False): """ Construct AS PATH. :param asn4: 4byte asn :param value: :param flags: """ # value example # [(2, [3257, 31027, 34848, 21465])], or [(3, [64606]), (2, [64624, 65515])] as_path_raw = '' for segment in value: as_seg_raw = '' seg_type = segment[0] as_path_list = segment[1] if seg_type not in [ self.AS_SET, self.AS_SEQUENCE, self.AS_CONFED_SET, self.AS_CONFED_SEQUENCE ]: assert excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_MALFORMED_ASPATH, data='') if asn4: # 4 bytes asn encode as_count = 0 for asn in as_path_list: as_count += 1 as_seg_raw += struct.pack('!I', asn) else: # 2 bytes asn encode as_count = 0 for asn in as_path_list: as_count += 1 as_seg_raw += struct.pack('!H', asn) as_path_raw += struct.pack('!B', seg_type) + struct.pack( '!B', as_count) + as_seg_raw if not flags: flags = self.FLAG if len(as_path_raw) > 255: flags += AttributeFlag.EXTENDED_LENGTH return struct.pack('!B', flags) + struct.pack('!B', self.ID) \ + struct.pack('!H', len(as_path_raw)) + as_path_raw else: return struct.pack('!B', flags) + struct.pack('!B', self.ID) \ + struct.pack('!B', len(as_path_raw)) + as_path_raw
def construct(self, value, flags=None): """ construct a CLUSTER_LIST path attribute :param value: :param flags: """ cluster_raw = '' if not flags: flags = self.FLAG try: for cluster in value: cluster_raw += IPv4Address(cluster).packed return struct.pack("!B", flags) + struct.pack('!B', self.ID) \ + struct.pack("!B", len(cluster_raw)) + cluster_raw except Exception: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=struct.pack('B', flags))
def parse(self, value): """ parse BGP community. :param value: """ community = [] if value: try: length = len(value) / 2 value_list = list(struct.unpack('!%dH' % length, value)) while value_list: value_type = value_list[0] * 16 * 16 * 16 * 16 + value_list[1] if 'UNKNOW' != self.to_string(value_type): community.append(self.to_string(value_type)) else: community.append("%s:%s" % (value_list[0], value_list[1])) value_list = value_list[2:] except Exception: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=value) return community
def parse_attributes(data, asn4=False): """ Parses an RFC4271 encoded blob of BGP attributes into a list :param data: :param asn4: support 4 bytes asn or not :return: """ attributes = {} postfix = data while len(postfix) > 0: try: flags, type_code = struct.unpack('!BB', postfix[:2]) if flags & AttributeFlag.EXTENDED_LENGTH: attr_len = struct.unpack('!H', postfix[2:4])[0] attr_value = postfix[4:4 + attr_len] postfix = postfix[4 + attr_len:] # Next attribute else: # standard 1-octet length attr_len = ord(postfix[2]) attr_value = postfix[3:3 + attr_len] postfix = postfix[3 + attr_len:] # Next attribute except Exception as e: LOG.error(e) error_str = traceback.format_exc() LOG.debug(error_str) raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_MALFORMED_ATTR_LIST, data='') if type_code == bgp_cons.BGPTYPE_ORIGIN: decode_value = Origin().parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_AS_PATH: decode_value = ASPath().parse(value=attr_value, asn4=asn4) elif type_code == bgp_cons.BGPTYPE_NEXT_HOP: decode_value = NextHop().parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_MULTI_EXIT_DISC: decode_value = MED().parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_LOCAL_PREF: decode_value = LocalPreference().parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_ATOMIC_AGGREGATE: decode_value = AtomicAggregate().parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_AGGREGATOR: decode_value = Aggregator().parse(value=attr_value, asn4=asn4) elif type_code == bgp_cons.BGPTYPE_COMMUNITIES: decode_value = Community().parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_ORIGINATOR_ID: decode_value = OriginatorID().parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_CLUSTER_LIST: decode_value = ClusterList().parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_NEW_AS_PATH: decode_value = ASPath().parse(value=attr_value, asn4=True) elif type_code == bgp_cons.BGPTYPE_NEW_AGGREGATOR: decode_value = Aggregator().parse(value=attr_value, asn4=True) else: decode_value = repr(attr_value) attributes[type_code] = decode_value return attributes