def parse_peer_down_notification(msg): """ This message is used to indicate that a peering session was terminated. :param msg: :return: """ # 0 1 2 3 4 5 6 7 8 # +-+-+-+-+-+-+-+-+ # | Reason | 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Data (present if Reason = 1, 2 or 3) | # ~ ~ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ LOG.info('decode peer down notification') reason = int(binascii.b2a_hex(msg[0]), 16) LOG.info('reason: %s' % reason) data = msg[1:] if reason == 1: LOG.info( 'Reason : 1 The local system closed the session. Following the ' 'Reason is a BGP PDU containing a BGP NOTIFICATION message that' 'would have been sent to the peer') Notification().parse(message=data) elif reason == 2: LOG.info( 'Reason :2 The local system closed the session. No notification' 'message was sent. Following the reason code is a two-byte field' 'containing the code corresponding to the FSM Event which caused' 'the system to close the session (see Section 8.1 of [RFC4271]).' 'Two bytes both set to zero are used to indicate that no relevant' 'Event code is defined') elif reason == 3: LOG.info( 'Reason : 3 The remote system closed the session with a notification' 'message. Following the Reason is a BGP PDU containing the BGP' 'NOTIFICATION message as received from the peer.') elif reason == 4: LOG.info( 'Reason : 4 The remote system closed the session without a notification message' ) else: LOG.waring('unknown peer down notification reason') return reason
def send_notification(self, error, sub_error, data=b''): """ send BGP notification message :param error: :param sub_error: :param data: :return: """ self.msg_sent_stat['Notifications'] += 1 LOG.info( "[%s]Send a BGP Notification message to the peer [Error: %s, Suberror: %s, Error data: %s ]", self.factory.peer_addr, error, sub_error, repr(data)) # message statistic self.msg_sent_stat['Notifications'] += 1 # construct message msg_notification = Notification().construct(error, sub_error, data) # send message self.transport.write(msg_notification)
def parse_route_mirroring_msg(msg): """ Route Mirroring messages are used for verbatim duplication of messages as received. Following the common BMP header and per-peer header is a set of TLVs that contain information about a message or set of messages. :param msg: :return: """ LOG.debug('decode route mirroring message') msg_dict = {} open_l = [] update = [] notification = [] route_refresh = [] while msg: mirror_type, length = struct.unpack('!HH', msg[0:4]) mirror_value = msg[4:4 + length] msg = msg[4 + length:] if mirror_type == 0: # BGP message type bgp_msg_type = struct.unpack('!B', mirror_value[18])[0] LOG.debug('bgp message type=%s' % bgp_msg_type) bgp_msg_body = mirror_value[bgp_cons.HDR_LEN:] if bgp_msg_type == 2: # Update message bgp_update_msg = Update().parse(None, bgp_msg_body, asn4=True) if bgp_update_msg['sub_error']: LOG.error( 'error: decode update message error!, error code: %s' % bgp_update_msg['sub_error']) LOG.error('Raw data: %s' % repr(bgp_update_msg['hex'])) else: update.append(bgp_update_msg) elif bgp_msg_type == 5: # Route Refresh message bgp_route_refresh_msg = RouteRefresh().parse( msg=bgp_msg_body) LOG.debug( 'bgp route refresh message: afi=%s,res=%s,safi=%s' % (bgp_route_refresh_msg[0], bgp_route_refresh_msg[1], bgp_route_refresh_msg[2])) route_refresh.append(bgp_route_refresh_msg) elif bgp_msg_type == 1: # Open message open_msg = Open().parse(bgp_msg_body) open_l.append(open_msg) elif bgp_msg_type == 3: # Notification message notification_msg = Notification().parse(bgp_msg_body) notification.append(notification_msg) elif mirror_type == 1: # Information type. # Amount of this TLV is not specified but we can assume # only one per mirroring message is present. info_code_type = struct.unpack('!H', mirror_value)[0] msg_dict['1'] = info_code_type else: msg_dict[mirror_type] = binascii.unhexlify( binascii.hexlify(mirror_value)) LOG.info('unknow mirroring type, type = %s' % mirror_type) msg_dict['0'] = { 'update': update, 'route_refresh': route_refresh, 'open': open_l, 'notification': notification } return msg_dict
def parse_buffer(self): """ Parse TCP buffer data. :return: True or False """ buf = self._receive_buffer if len(buf) < bgp_cons.HDR_LEN: # Every BGP message is at least 19 octets. Maybe the rest # hasn't arrived yet. return False # Check whether the first 16 octets of the buffer consist of # the BGP marker (all bits one) if buf[:16] != 16 * b'\xff': self.fsm.header_error(bgp_cons.ERR_MSG_HDR_CONN_NOT_SYNC) return False # Parse the BGP header try: marker, length, msg_type = struct.unpack('!16sHB', buf[:bgp_cons.HDR_LEN]) except Exception as e: LOG.error(e) error_str = traceback.format_exc() LOG.debug(error_str) self.fsm.header_error(bgp_cons.ERR_MSG_HDR_CONN_NOT_SYNC) return False # Check the length of the message, must be less than 4096, bigger than 19 if length < bgp_cons.HDR_LEN or length > bgp_cons.MAX_LEN: self.fsm.header_error(bgp_cons.ERR_MSG_HDR_BAD_MSG_LEN, struct.pack('!H', length)) # Check whether the entire message is already available if len(buf) < length: return False msg = buf[bgp_cons.HDR_LEN:length] t = time.time() # the time when received that packet. try: if msg_type == bgp_cons.MSG_OPEN: try: self._open_received(timestamp=t, msg=msg) except excep.MessageHeaderError as e: LOG.error(e) self.fsm.header_error(suberror=e.sub_error) return False except excep.OpenMessageError as e: LOG.error(e) self.fsm.open_message_error(suberror=e.sub_error) return False elif msg_type == bgp_cons.MSG_UPDATE: self._update_received(timestamp=t, msg=msg) elif msg_type == bgp_cons.MSG_NOTIFICATION: self._notification_received(Notification().parse(msg)) elif msg_type == bgp_cons.MSG_KEEPALIVE: try: self._keepalive_received(timestamp=t, msg=msg) except excep.MessageHeaderError as e: LOG.error(e) self.fsm.header_error(suberror=e.sub_error) return False elif msg_type in (bgp_cons.MSG_ROUTEREFRESH, bgp_cons.MSG_CISCOROUTEREFRESH): route_refresh_msg = RouteRefresh().parse(msg) self._route_refresh_received(msg=route_refresh_msg, msg_type=msg_type) else: # unknown message type self.fsm.header_error(bgp_cons.ERR_MSG_HDR_BAD_MSG_TYPE, struct.pack('!H', msg_type)) except Exception as e: LOG.error(e) error_str = traceback.format_exc() LOG.debug(error_str) self._receive_buffer = self._receive_buffer[length:] return True
def test_construct(self): msg_hex = Notification().construct(error=3, suberror=5, data=b'\x00\x00') hope_msg = b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' \ b'\xff\xff\x00\x17\x03\x03\x05\x00\x00' self.assertEqual(hope_msg, msg_hex)
def test_parse(self): msg_hex = b'\x03\x05\x00\x00' noti_msg = Notification().parse(msg_hex) self.assertEqual((3, 5, b'\x00\x00'), noti_msg)