u_char mstream_getc(struct mstream *s, u_char *d) { u_char data; mstream_get(s, &data, sizeof(data)); if(d!=NULL) memcpy(d,&data,sizeof(data)); return data; }
u_int32_t mstream_get_ipv4(struct mstream *s, u_int32_t *d) { u_int32_t data; mstream_get(s, &data, sizeof(data)); if(d!=NULL) memcpy(d,&data,sizeof(data)); return data; }
u_int16_t mstream_getw(struct mstream *s, u_int16_t *d) { u_int16_t data; mstream_get(s, &data, sizeof(data)); data=ntohs(data); if(d!=NULL) memcpy(d,&data,sizeof(data)); return data; }
int process_zebra_bgp_message_notify(struct mstream *s, BGPDUMP_ENTRY *entry) { mstream_getc(s, &entry->body.zebra_message.error_code); mstream_getc(s, &entry->body.zebra_message.sub_error_code); entry->body.zebra_message.notify_len = entry->body.zebra_message.size - 21; if(entry->body.zebra_message.notify_len > 0) { entry->body.zebra_message.notify_data = malloc(entry->body.zebra_message.notify_len); mstream_get(s, entry->body.zebra_message.notify_data, entry->body.zebra_message.notify_len); } return 1; }
int process_zebra_bgp_message_open(struct mstream *s, BGPDUMP_ENTRY *entry, u_int8_t asn_len) { mstream_getc(s, &entry->body.zebra_message.version); read_asn(s, &entry->body.zebra_message.my_as, asn_len); mstream_getw(s, &entry->body.zebra_message.hold_time); mstream_get_ipv4(s, &entry->body.zebra_message.bgp_id.s_addr); mstream_getc(s, &entry->body.zebra_message.opt_len); if(entry->body.zebra_message.opt_len) { entry->body.zebra_message.opt_data = malloc(entry->body.zebra_message.opt_len); mstream_get(s, entry->body.zebra_message.opt_data, entry->body.zebra_message.opt_len); } return 1; }
int process_mrtd_table_dump_v2_ipv6_unicast(struct mstream *s, BGPDUMP_ENTRY *entry){ #ifdef BGPDUMP_HAVE_IPV6 BGPDUMP_TABLE_DUMP_V2_PREFIX *prefixdata; prefixdata = &entry->body.mrtd_table_dump_v2_prefix; uint16_t i; prefixdata->afi = AFI_IP6; prefixdata->safi = SAFI_UNICAST; mstream_getl(s, &prefixdata->seq); mstream_getc(s, &prefixdata->prefix_length); bzero(&prefixdata->prefix.v6_addr.s6_addr, 16); mstream_get(s, &prefixdata->prefix.v6_addr.s6_addr, (prefixdata->prefix_length+7)/8); mstream_getw(s, &prefixdata->entry_count); prefixdata->entries = malloc(sizeof(BGPDUMP_TABLE_DUMP_V2_ROUTE_ENTRY) * prefixdata->entry_count); if(prefixdata->entries == NULL){ syslog(LOG_ERR, "process_mrtd_table_dump_v2_ipv6_unicast: failed to allocate memory for entry table"); return 0; } for(i=0; i < prefixdata->entry_count; i++){ BGPDUMP_TABLE_DUMP_V2_ROUTE_ENTRY *e; e = &prefixdata->entries[i]; mstream_getw(s, &e->peer_index); e->peer = &table_dump_v2_peer_index_table->entries[e->peer_index]; mstream_getl(s, &e->originated_time); process_attr_init(entry); entry->attr->len = e->attribute_length; process_attr_read(s, entry->attr, 4, NULL, 1); e->attr = entry->attr; entry->attr = NULL; } #endif return 1; }
// construct a partial mstream mstream_t mstream_copy(mstream_t *s, int len) { mstream_t copy = {0}; copy.start = s->start + s->position; copy.len = mstream_get(s, NULL, len); return copy; }
struct in_addr mstream_get_ipv4(struct mstream *s) { struct in_addr addr; mstream_get(s, &addr.s_addr, 4); return addr; }
void process_attr_read(struct mstream *s, struct attr *attr, u_int8_t asn_len, struct zebra_incomplete *incomplete, char mp_only_nexthop) { u_char flag; u_char type; u_int32_t len, end; u_int32_t truelen; struct unknown_attr *unknown; mstream_getw(s, &attr->len); if(attr->len == 0) return; attr->data=malloc(attr->len); /* Check the attributes are not truncated */ if(attr->len > mstream_can_read(s)) { truelen = mstream_can_read(s); memset(attr->data + truelen, 0, attr->len - truelen); } else { truelen = attr->len; } memcpy(attr->data, &s->start[s->position], truelen); end = s->position + truelen; while(s->position < end) { mstream_getc(s,&flag); mstream_getc(s,&type); if(flag & BGP_ATTR_FLAG_EXTLEN) len=mstream_getw(s,NULL); else len=mstream_getc(s,NULL); /* Take note of all attributes, including unknown ones */ if(type <= sizeof(attr->flag) * 8) attr->flag = attr->flag | ATTR_FLAG_BIT (type); switch(type) { case BGP_ATTR_ORIGIN: mstream_getc(s,&attr->origin); break; case BGP_ATTR_AS_PATH: attr->aspath = create_aspath(len, asn_len); mstream_get(s,attr->aspath->data,len); process_attr_aspath_string(attr->aspath); break; case BGP_ATTR_NEXT_HOP: mstream_get_ipv4(s,&attr->nexthop.s_addr); break; case BGP_ATTR_MULTI_EXIT_DISC: mstream_getl(s,&attr->med); break; case BGP_ATTR_LOCAL_PREF: mstream_getl(s,&attr->local_pref); break; case BGP_ATTR_ATOMIC_AGGREGATE: break; case BGP_ATTR_AGGREGATOR: read_asn(s, &attr->aggregator_as, asn_len); mstream_get_ipv4(s,&attr->aggregator_addr.s_addr); break; case BGP_ATTR_COMMUNITIES: attr->community = malloc(sizeof(struct community)); attr->community->size = len / 4; attr->community->val = malloc(len); mstream_get(s,attr->community->val,len); attr->community->str = NULL; process_attr_community_string(attr->community); break; case BGP_ATTR_MP_REACH_NLRI: if(attr->mp_info == NULL) { attr->mp_info = malloc(sizeof(struct mp_info)); memset(attr->mp_info, 0, sizeof(struct mp_info)); } if(mp_only_nexthop) process_mp_announce_only_nexthop(s, attr->mp_info, len, incomplete); else process_mp_announce(s, attr->mp_info, len, incomplete); break; case BGP_ATTR_MP_UNREACH_NLRI: if(attr->mp_info == NULL) { attr->mp_info = malloc(sizeof(struct mp_info)); memset(attr->mp_info, 0, sizeof(struct mp_info)); } process_mp_withdraw(s, attr->mp_info, len, incomplete); case BGP_ATTR_NEW_AS_PATH: attr->new_aspath = create_aspath(len, ASN32_LEN); mstream_get(s,attr->new_aspath->data,len); process_attr_aspath_string(attr->new_aspath); /* AS_CONFED_SEQUENCE and AS_CONFED_SET segments invalid in NEW_AS_PATH */ check_new_aspath(attr->new_aspath); break; case BGP_ATTR_NEW_AGGREGATOR: read_asn(s, &attr->new_aggregator_as, ASN32_LEN); mstream_get_ipv4(s,&attr->new_aggregator_addr.s_addr); break; case BGP_ATTR_ORIGINATOR_ID: mstream_get_ipv4(s,&attr->originator_id.s_addr); break; case BGP_ATTR_CLUSTER_LIST: attr->cluster = malloc(sizeof(struct cluster_list)); attr->cluster->length = len/4; attr->cluster->list = malloc((attr->cluster->length) * sizeof(struct in_addr)); int cluster_index; for (cluster_index=0;cluster_index<attr->cluster->length;cluster_index++) mstream_get_ipv4(s,&attr->cluster->list[cluster_index].s_addr); break; default: /* Unknown attribute. Save as is */ attr->unknown_num++; attr->unknown = realloc(attr->unknown, attr->unknown_num * sizeof(struct unknown_attr)); /* Pointer to the unknown attribute we want to fill in */ unknown = attr->unknown + attr->unknown_num - 1; /* Work around bogus attribute lengths */ if(s->position + len > end) unknown->real_len = end - s->position; else unknown->real_len = len; unknown->flag = flag; unknown->type = type; unknown->len = len; unknown->raw = malloc(unknown->real_len + ((flag & BGP_ATTR_FLAG_EXTLEN) ? 4 : 3)); unknown->raw[0] = flag; unknown->raw[1] = type; if(flag & BGP_ATTR_FLAG_EXTLEN) { unknown->raw[2] = (len & 0xFF00) >> 8; unknown->raw[3] = len & 0xFF; mstream_get(s, unknown->raw + 4, unknown->real_len); } else { unknown->raw[2] = len; mstream_get(s, unknown->raw + 3, unknown->real_len); } break; }
int process_zebra_bgp_message(struct mstream *s,BGPDUMP_ENTRY *entry, u_int8_t asn_len) { u_char marker[16]; /* BGP marker */ read_asn(s, &entry->body.zebra_message.source_as, asn_len); read_asn(s, &entry->body.zebra_message.destination_as, asn_len); mstream_getw(s,&entry->body.zebra_message.interface_index); mstream_getw(s,&entry->body.zebra_message.address_family); /* Initialize announce and withdraw arrays: if there is a * parse error, they will not be free()d, and we will not segfault. */ entry->body.zebra_message.withdraw = NULL; entry->body.zebra_message.announce = NULL; entry->body.zebra_message.opt_len = 0; entry->body.zebra_message.opt_data = NULL; entry->body.zebra_message.notify_len = 0; entry->body.zebra_message.notify_data = NULL; switch(entry->body.zebra_message.address_family) { case AFI_IP: mstream_get_ipv4(s,&entry->body.zebra_message.source_ip.v4_addr.s_addr); mstream_get_ipv4(s,&entry->body.zebra_message.destination_ip.v4_addr.s_addr); mstream_get (s, marker, 16); break; #ifdef BGPDUMP_HAVE_IPV6 case AFI_IP6: mstream_get(s,&entry->body.zebra_message.source_ip.v6_addr.s6_addr, 16); mstream_get(s,&entry->body.zebra_message.destination_ip.v6_addr.s6_addr, 16); mstream_get (s, marker, 16); break; #endif case 0xFFFF: /* Zebra doesn't dump ifindex or src/dest IPs in OPEN * messages. Work around it. */ if (entry->body.zebra_message.interface_index == 0xFFFF) { memset(marker, 0xFF, 4); mstream_get (s, marker + 4, 12); entry->body.zebra_message.interface_index = 0; entry->body.zebra_message.address_family = AFI_IP; entry->body.zebra_message.source_ip.v4_addr.s_addr = 0; entry->body.zebra_message.destination_ip.v4_addr.s_addr = 0; break; } /* Note fall through! If we don't recognize this type of data corruption, we say * the address family is unsupported (since FFFF is not a valid address family) */ default: /* unsupported address family */ syslog(LOG_WARNING, "process_zebra_bgp_message: unsupported AFI %d", entry->body.zebra_message.address_family); return 0; } if(memcmp(marker, "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377", 16) != 0) { /* bad marker... ignore packet */ syslog(LOG_WARNING, "bgp_message: bad marker: %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x", marker[0],marker[1],marker[2],marker[3],marker[4],marker[5],marker[6],marker[7], marker[8],marker[9],marker[10],marker[11],marker[12],marker[13],marker[14],marker[15]); return 0; } mstream_getw (s,&entry->body.zebra_message.size); mstream_getc (s,&entry->body.zebra_message.type); entry->body.zebra_message.cut_bytes = entry->body.zebra_message.size - 19 - mstream_can_read(s); switch(entry->body.zebra_message.type) { case BGP_MSG_OPEN: return process_zebra_bgp_message_open(s,entry, asn_len); case BGP_MSG_UPDATE: return process_zebra_bgp_message_update(s,entry, asn_len); case BGP_MSG_NOTIFY: return process_zebra_bgp_message_notify(s,entry); case BGP_MSG_KEEPALIVE: /* Nothing to do */ return 1; case BGP_MSG_ROUTE_REFRESH_01: /* Not implemented yet */ syslog(LOG_WARNING, "bgp_message: MSG_ROUTE_REFRESH_01 not implemented yet"); return 0; case BGP_MSG_ROUTE_REFRESH: /* Not implemented yet */ syslog(LOG_WARNING, "bgp_message: MSG_ROUTE_REFRESH not implemented yet"); return 0; default: syslog(LOG_WARNING, "bgp_message: unknown BGP message type %d", entry->body.zebra_message.type); return 0; } }
int process_zebra_bgp_state_change(struct mstream *s,BGPDUMP_ENTRY *entry, u_int8_t asn_len) { read_asn(s, &entry->body.zebra_state_change.source_as, asn_len); read_asn(s, &entry->body.zebra_state_change.destination_as, asn_len); /* Work around Zebra dump corruption. * N.B. I don't see this in quagga 0.96.4 any more. Is it fixed? */ if (entry->length == 8) { syslog(LOG_NOTICE, "process_zebra_bgp_state_change: 8-byte state change (zebra bug?)"); mstream_getw(s,&entry->body.zebra_state_change.old_state); mstream_getw(s,&entry->body.zebra_state_change.new_state); /* Fill in with dummy values */ entry->body.zebra_state_change.interface_index = 0; entry->body.zebra_state_change.address_family = AFI_IP; entry->body.zebra_state_change.source_ip.v4_addr.s_addr = 0; entry->body.zebra_state_change.destination_ip.v4_addr.s_addr = 0; return 1; } mstream_getw(s,&entry->body.zebra_state_change.interface_index); mstream_getw(s,&entry->body.zebra_state_change.address_family); switch(entry->body.zebra_state_change.address_family) { case AFI_IP: // length could be 20 or 24 (asn16 vs asn32) if(entry->length != 20 && entry->length != 24) { syslog(LOG_WARNING, "process_zebra_bgp_state_change: bad length %d", entry->length); return 0; } mstream_get_ipv4(s,&entry->body.zebra_state_change.source_ip.v4_addr.s_addr); mstream_get_ipv4(s,&entry->body.zebra_state_change.destination_ip.v4_addr.s_addr); break; #ifdef BGPDUMP_HAVE_IPV6 case AFI_IP6: // length could be 44 or 48 (asn16 vs asn32) if(entry->length != 44 && entry->length != 48) { syslog(LOG_WARNING, "process_zebra_bgp_state_change: bad length %d", entry->length); return 0; } mstream_get(s, &entry->body.zebra_state_change.source_ip.v6_addr.s6_addr, 16); mstream_get(s, &entry->body.zebra_state_change.destination_ip.v6_addr.s6_addr, 16); break; #endif default: syslog(LOG_WARNING, "process_zebra_bgp_state_change: unknown AFI %d", entry->body.zebra_state_change.address_family); return 0; } mstream_getw(s,&entry->body.zebra_state_change.old_state); mstream_getw(s,&entry->body.zebra_state_change.new_state); return 1; }
int process_mrtd_table_dump_v2_peer_index_table(struct mstream *s,BGPDUMP_ENTRY *entry) { BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE *t; uint16_t i; uint8_t peertype; uint16_t view_name_len; if(table_dump_v2_peer_index_table){ if(table_dump_v2_peer_index_table->entries) free(table_dump_v2_peer_index_table->entries); free(table_dump_v2_peer_index_table); } table_dump_v2_peer_index_table = malloc(sizeof(BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE)); t = table_dump_v2_peer_index_table; t->entries = NULL; mstream_get_ipv4(s,(uint32_t *)&t->local_bgp_id); mstream_getw(s,&view_name_len); strcpy(t->view_name, ""); // view_name_len is without trailing \0 if(view_name_len+1 > BGPDUMP_TYPE_TABLE_DUMP_V2_MAX_VIEWNAME_LEN) { syslog(LOG_WARNING, "process_mrtd_table_dump_v2_peer_index_table: view name length more than maximum length (%d), ignoring view name", BGPDUMP_TYPE_TABLE_DUMP_V2_MAX_VIEWNAME_LEN); } else { mstream_get(s, t->view_name, view_name_len); t->view_name[view_name_len] = 0; } mstream_getw(s,&t->peer_count); t->entries = malloc(sizeof(BGPDUMP_TABLE_DUMP_V2_PEER_INDEX_TABLE_ENTRY) * t->peer_count); if(t->entries == NULL){ syslog(LOG_ERR, "process_mrtd_table_dump_v2_peer_index_table: failed to allocate memory for index table"); return 0; } for(i=0; i < t->peer_count; i++) { mstream_getc(s,&peertype); #ifdef BGPDUMP_HAVE_IPV6 if(peertype & BGPDUMP_PEERTYPE_TABLE_DUMP_V2_AFI_IP6) t->entries[i].afi = AFI_IP6; else #endif t->entries[i].afi = AFI_IP; mstream_get_ipv4(s,(uint32_t *)&t->entries[i].peer_bgp_id); if(t->entries[i].afi == AFI_IP) mstream_get_ipv4(s,&t->entries[i].peer_ip.v4_addr.s_addr); #ifdef BGPDUMP_HAVE_IPV6 else mstream_get(s, &t->entries[i].peer_ip.v6_addr.s6_addr, 16); #endif if(peertype & BGPDUMP_PEERTYPE_TABLE_DUMP_V2_AS4) read_asn(s, &t->entries[i].peer_as, 4); else read_asn(s, &t->entries[i].peer_as, 2); } return 0; }
int process_mrtd_table_dump(struct mstream *s,BGPDUMP_ENTRY *entry) { int afi = entry->subtype; u_int8_t asn_len; u_int32_t temp_time = 0; mstream_getw(s,&entry->body.mrtd_table_dump.view); mstream_getw(s,&entry->body.mrtd_table_dump.sequence); switch(afi) { case BGPDUMP_SUBTYPE_MRTD_TABLE_DUMP_AFI_IP: case BGPDUMP_SUBTYPE_MRTD_TABLE_DUMP_AFI_IP_32BIT_AS: mstream_get_ipv4(s, &entry->body.mrtd_table_dump.prefix.v4_addr.s_addr); break; #ifdef BGPDUMP_HAVE_IPV6 case BGPDUMP_SUBTYPE_MRTD_TABLE_DUMP_AFI_IP6: case BGPDUMP_SUBTYPE_MRTD_TABLE_DUMP_AFI_IP6_32BIT_AS: mstream_get(s, &entry->body.mrtd_table_dump.prefix.v6_addr.s6_addr, 16); break; #endif default: syslog(LOG_WARNING, "process_mrtd_table_dump: unknown AFI %d", afi); mstream_get(s, NULL, mstream_can_read(s)); return 0; } mstream_getc(s,&entry->body.mrtd_table_dump.mask); mstream_getc(s,&entry->body.mrtd_table_dump.status); mstream_getl(s,&temp_time); (entry->body).mrtd_table_dump.uptime = temp_time; switch(afi) { case BGPDUMP_SUBTYPE_MRTD_TABLE_DUMP_AFI_IP: case BGPDUMP_SUBTYPE_MRTD_TABLE_DUMP_AFI_IP_32BIT_AS: mstream_get_ipv4(s, &entry->body.mrtd_table_dump.peer_ip.v4_addr.s_addr); break; #ifdef BGPDUMP_HAVE_IPV6 case BGPDUMP_SUBTYPE_MRTD_TABLE_DUMP_AFI_IP6: case BGPDUMP_SUBTYPE_MRTD_TABLE_DUMP_AFI_IP6_32BIT_AS: mstream_get(s, &entry->body.mrtd_table_dump.peer_ip.v6_addr.s6_addr, 16); break; #endif } switch(afi) { case BGPDUMP_SUBTYPE_MRTD_TABLE_DUMP_AFI_IP: case BGPDUMP_SUBTYPE_MRTD_TABLE_DUMP_AFI_IP6: asn_len = ASN16_LEN; break; case BGPDUMP_SUBTYPE_MRTD_TABLE_DUMP_AFI_IP_32BIT_AS: case BGPDUMP_SUBTYPE_MRTD_TABLE_DUMP_AFI_IP6_32BIT_AS: asn_len = ASN32_LEN; break; default: /* Not reached. Keep compiler happy */ asn_len = 0; break; } read_asn(s,&entry->body.mrtd_table_dump.peer_as, asn_len); process_attr_init(entry); process_attr_read(s, entry->attr, asn_len, NULL, 0); return 1; }