📄 bgp_packet.c
字号:
int ret; u_char version; u_char optlen; u_int16_t holdtime; u_int16_t send_holdtime; as_t remote_as; struct peer *realpeer; struct in_addr remote_id; int capability; char notify_data_remote_as[2]; char notify_data_remote_id[4]; realpeer = NULL; /* Parse open packet. */ version = stream_getc (peer->ibuf); memcpy (notify_data_remote_as, stream_pnt (peer->ibuf), 2); remote_as = stream_getw (peer->ibuf); holdtime = stream_getw (peer->ibuf); memcpy (notify_data_remote_id, stream_pnt (peer->ibuf), 4); remote_id.s_addr = stream_get_ipv4 (peer->ibuf); /* Receive OPEN message log */ if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s rcv OPEN, version %d, remote-as %d, holdtime %d, id %s", peer->host, version, remote_as, holdtime, inet_ntoa (remote_id)); /* Lookup peer from Open packet. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { int as = 0; realpeer = peer_lookup_with_open (&peer->su, remote_as, &remote_id, &as); if (! realpeer) { /* Peer's source IP address is check in bgp_accept(), so this must be AS number mismatch or remote-id configuration mismatch. */ if (as) { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s bad OPEN, wrong router identifier %s", peer->host, inet_ntoa (remote_id)); bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_BGP_IDENT, notify_data_remote_id, 4); } else { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s bad OPEN, remote AS is %d, expected %d", peer->host, remote_as, peer->as); bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as, 2); } return -1; } } /* When collision is detected and this peer is closed. Retrun immidiately. */ ret = bgp_collision_detect (peer, remote_id); if (ret < 0) return ret; /* Hack part. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { if (ret == 0 && realpeer->status != Active && realpeer->status != OpenSent && realpeer->status != OpenConfirm) { if (BGP_DEBUG (events, EVENTS)) zlog_info ("%s [Event] peer's status is %s close connection", realpeer->host, LOOKUP (bgp_status_msg, peer->status)); return -1; } if (BGP_DEBUG (events, EVENTS)) zlog_info ("%s [Event] Transfer temporary BGP peer to existing one", peer->host); bgp_stop (realpeer); /* Transfer file descriptor. */ realpeer->fd = peer->fd; peer->fd = -1; /* Transfer input buffer. */ stream_free (realpeer->ibuf); realpeer->ibuf = peer->ibuf; realpeer->packet_size = peer->packet_size; peer->ibuf = NULL; /* Transfer status. */ realpeer->status = peer->status; bgp_stop (peer); /* peer pointer change. Open packet send to neighbor. */ peer = realpeer; bgp_open_send (peer); if (peer->fd < 0) { zlog_err ("bgp_open_receive peer's fd is negative value %d", peer->fd); return -1; } BGP_READ_ON (peer->t_read, bgp_read, peer->fd); } /* remote router-id check. */ if (remote_id.s_addr == 0 || ntohl (remote_id.s_addr) >= 0xe0000000 || ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr)) { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s bad OPEN, wrong router identifier %s", peer->host, inet_ntoa (remote_id)); bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_BGP_IDENT, notify_data_remote_id, 4); return -1; } /* Set remote router-id */ peer->remote_id = remote_id; /* Peer BGP version check. */ if (version != BGP_VERSION_4) { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s bad protocol version, remote requested %d, local request %d", peer->host, version, BGP_VERSION_4); bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_VERSION, "\x04", 1); return -1; } /* Check neighbor as number. */ if (remote_as != peer->as) { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s bad OPEN, remote AS is %d, expected %d", peer->host, remote_as, peer->as); bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as, 2); return -1; } /* From the rfc: Upon receipt of an OPEN message, a BGP speaker MUST calculate the value of the Hold Timer by using the smaller of its configured Hold Time and the Hold Time received in the OPEN message. The Hold Time MUST be either zero or at least three seconds. An implementation may reject connections on the basis of the Hold Time. */ if (holdtime < 3 && holdtime != 0) { bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNACEP_HOLDTIME); return -1; } /* From the rfc: A reasonable maximum time between KEEPALIVE messages would be one third of the Hold Time interval. KEEPALIVE messages MUST NOT be sent more frequently than one per second. An implementation MAY adjust the rate at which it sends KEEPALIVE messages as a function of the Hold Time interval. */ if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) send_holdtime = peer->holdtime; else send_holdtime = peer->bgp->default_holdtime; if (holdtime < send_holdtime) peer->v_holdtime = holdtime; else peer->v_holdtime = send_holdtime; peer->v_keepalive = peer->v_holdtime / 3; /* Open option part parse. */ capability = 0; optlen = stream_getc (peer->ibuf); if (optlen != 0) { ret = bgp_open_option_parse (peer, optlen, &capability); if (ret < 0) return ret; stream_forward (peer->ibuf, optlen); } else { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s rcvd OPEN w/ OPTION parameter len: 0", peer->host); } /* Override capability. */ if (! capability || CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { peer->afc_nego[AFI_IP][SAFI_UNICAST] = peer->afc[AFI_IP][SAFI_UNICAST]; peer->afc_nego[AFI_IP][SAFI_MULTICAST] = peer->afc[AFI_IP][SAFI_MULTICAST]; peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST]; peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST]; } /* Get sockname. */ bgp_getsockname (peer); BGP_EVENT_ADD (peer, Receive_OPEN_message); peer->packet_size = 0; if (peer->ibuf) stream_reset (peer->ibuf); return 0;}/* Parse BGP Update packet and make attribute object. */intbgp_update_receive (struct peer *peer, bgp_size_t size){ int ret; u_char *end; struct stream *s; struct attr attr; bgp_size_t attribute_len; bgp_size_t update_len; bgp_size_t withdraw_len; struct bgp_nlri update; struct bgp_nlri withdraw; struct bgp_nlri mp_update; struct bgp_nlri mp_withdraw; char attrstr[BUFSIZ]; /* Status must be Established. */ if (peer->status != Established) { zlog_err ("%s [FSM] Update packet received under status %s", peer->host, LOOKUP (bgp_status_msg, peer->status)); bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); return -1; } /* Set initial values. */ memset (&attr, 0, sizeof (struct attr)); memset (&update, 0, sizeof (struct bgp_nlri)); memset (&withdraw, 0, sizeof (struct bgp_nlri)); memset (&mp_update, 0, sizeof (struct bgp_nlri)); memset (&mp_withdraw, 0, sizeof (struct bgp_nlri)); s = peer->ibuf; end = stream_pnt (s) + size; /* RFC1771 6.3 If the Unfeasible Routes Length or Total Attribute Length is too large (i.e., if Unfeasible Routes Length + Total Attribute Length + 23 exceeds the message Length), then the Error Subcode is set to Malformed Attribute List. */ if (stream_pnt (s) + 2 > end) { zlog_err ("%s [Error] Update packet error" " (packet length is short for unfeasible length)", peer->host); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); return -1; } /* Unfeasible Route Length. */ withdraw_len = stream_getw (s); /* Unfeasible Route Length check. */ if (stream_pnt (s) + withdraw_len > end) { zlog_err ("%s [Error] Update packet error" " (packet unfeasible length overflow %d)", peer->host, withdraw_len); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); return -1; } /* Unfeasible Route packet format check. */ if (withdraw_len > 0) { ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), withdraw_len); if (ret < 0) return -1; if (BGP_DEBUG (packet, PACKET_RECV)) zlog_info ("%s [Update:RECV] Unfeasible NLRI received", peer->host); withdraw.afi = AFI_IP; withdraw.safi = SAFI_UNICAST; withdraw.nlri = stream_pnt (s); withdraw.length = withdraw_len; stream_forward (s, withdraw_len); } /* Attribute total length check. */ if (stream_pnt (s) + 2 > end) { zlog_warn ("%s [Error] Packet Error" " (update packet is short for attribute length)", peer->host); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); return -1; } /* Fetch attribute total length. */ attribute_len = stream_getw (s); /* Attribute length check. */ if (stream_pnt (s) + attribute_len > end) { zlog_warn ("%s [Error] Packet Error" " (update packet attribute length overflow %d)", peer->host, attribute_len); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); return -1; } /* Parse attribute when it exists. */ if (attribute_len) { ret = bgp_attr_parse (peer, &attr, attribute_len, &mp_update, &mp_withdraw); if (ret < 0) return -1; } /* Logging the attribute. */ if (BGP_DEBUG (update, UPDATE_IN)) { bgp_dump_attr (peer, &attr, attrstr, BUFSIZ); zlog (peer->log, LOG_INFO, "%s rcvd UPDATE w/ attr: %s", peer->host, attrstr); } /* Network Layer Reachability Information. */ update_len = end - stream_pnt (s); if (update_len) { /* Check NLRI packet format and prefix length. */ ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), update_len); if (ret < 0) return -1; /* Set NLRI portion to structure. */ update.afi = AFI_IP; update.safi = SAFI_UNICAST; update.nlri = stream_pnt (s); update.length = update_len; stream_forward (s, update_len); } /* NLRI is processed only when the peer is configured specific Address Family and Subsequent Address Family. */ if (peer->afc[AFI_IP][SAFI_UNICAST]) { if (withdraw.length) bgp_nlri_parse (peer, NULL, &withdraw); if (update.length) { /* We check well-known attribute only for IPv4 unicast update. */ ret = bgp_attr_check (peer, &attr); if (ret < 0) return -1; bgp_nlri_parse (peer, &attr, &update); } } if (peer->afc[AFI_IP][SAFI_MULTICAST]) { if (mp_update.length && mp_update.afi == AFI_IP && mp_update.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, &attr, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); } if (peer->afc[AFI_IP6][SAFI_UNICAST]) { if (mp_update.length && mp_update.afi == AFI_IP6 && mp_update.safi == SAFI_UNICAST) bgp_nlri_parse (peer, &attr, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP6 && mp_withdraw.safi == SAFI_UNICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); } if (peer->afc[AFI_IP6][SAFI_MULTICAST]) { if (mp_update.length && mp_update.afi == AFI_IP6 && mp_update.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, &attr, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP6 && mp_withdraw.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); } if (peer->afc[AFI_IP][SAFI_MPLS_VPN]) { if (mp_update.length && mp_update.afi == AFI_IP && mp_update.safi == BGP_SAFI_VPNV4) bgp_nlri_parse_vpnv4 (peer, &attr, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == BGP_SAFI_VPNV4) bgp_nlri_parse_vpnv4 (peer, NULL, &mp_withdraw); } /* Everything is done. We unintern temporary structures which interned in bgp_attr_parse(). */ if (attr.aspath) aspath_unintern (attr.aspath); if (attr.community) community_unintern (attr.community); if (attr.ecommunity) ecommunity_unintern (attr.ecommunity); if (attr.cluster) cluster_unintern (attr.cluster); if (attr.transit) transit_unintern (attr.transit); /* If peering is stopped due to some reason, do not generate BGP event. */ if (peer->status != Established) return 0; /* Increment packet counter. */ peer->update_in++; peer->update_time = time (NULL); /* Generate BGP event. */ BGP_EVENT_ADD (peer, Receive_UPDATE_message); return 0;}/* Notify message treatment function. */voidbgp_notify_receive (struct peer *peer, bgp_size_t size){ struct bgp_notify bgp_notify; if (peer->notify.data) { XFREE (MTYPE_TMP, peer->notify.data); peer->notify.data = NULL; peer->notify.length = 0; } bgp_notify.code = stream_getc (peer->ibuf); bgp_notify.subcode = stream_getc (peer->ibuf); bgp_notify.length = size - 2; bgp_notify.data = NULL; /* Preserv notify code and sub code. */ peer->notify.code = bgp_notify.code; peer->notify.subcode = bgp_notify.subcode; /* For further diagnostic record returned Data. */ if (bgp_notify.length) { peer->notify.length = size - 2; peer->notify.data = XMALLOC (MTYPE_TMP, size - 2); memcpy (peer->notify.data, stream_pnt (peer->ibuf), size - 2); } /* For debug */ { int i; int first = 0; char c[4]; if (bgp_notify.length) { bgp_notify.data = XMALLOC (MTYPE_TMP, bgp_notify.length * 3); for (i = 0; i < bgp_notify.length; i++) if (first) { sprintf (c, " %02x", stream_getc (peer->ibuf)); strcat (bgp_notify.data, c); } else { first = 1; sprintf (c, "%02x", stream_getc (peer->ibuf)); strcpy (bgp_notify.data, c); } } bgp_notify_print(peer, &bgp_notify, "received"); if (bgp_notify.data) XFREE (MTYPE_TMP, bgp_notify.data); } /* peer count update */ peer->notify_in++; if (peer->status == Established) peer->last_reset = PEER_DOWN_NOTIFY_RECEIVED; /* We have to check for Notify with Unsupported Optional Parameter. in that case we fallback to open without the capability option. But this done in bgp_stop. We just mark it here to avoid changing the fsm tables. */ if (bgp_notify.code == BGP_NOTIFY_OPEN_ERR && bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM ) UNSET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN); /* Also apply to Unsupported Capability until remote router support capability. */ if (bgp_notify.code == BGP_NOTIFY_OPEN_ERR && bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_CAPBL) UNSET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN); BGP_EVENT_ADD (peer, Receive_NOTIFICATION_message);}/* Keepalive treatment function -- get keepalive send keepalive */voidbgp_keepalive_receive (struct peer *peer, bgp_size_t size){ if (BGP_DEBUG (keepalive, KEEPALIVE)) zlog_info ("%s KEEPALIVE rcvd", peer->host); BGP_EVENT_ADD (peer, Receive_KEEPALIVE_message);}/* Route refresh message is received. */voidbgp_route_refresh_receive (struct peer *peer, bgp_size_t size){ afi_t afi; safi_t safi; u_char reserved; struct stream *s;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -