From: Katerina Kubecova Date: Wed, 21 May 2025 10:09:49 +0000 (+0200) Subject: mrt: first version of mrt parse. Not parsing bgp routes, but all of the other mrt... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4df24a82092401eab83f8bcac0d4f312fc72ce90;p=thirdparty%2Fbird.git mrt: first version of mrt parse. Not parsing bgp routes, but all of the other mrt messages (which will be deleted later commits). --- diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index e853624b8..51193d170 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1366,7 +1366,7 @@ bgp_decode_attr(struct bgp_parse_state *s, uint code, uint flags, byte *data, ui * by an (uncached) &rta. */ ea_list * -bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len) +bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len, void (*parse_error)(struct bgp_parse_state *, uint)) { struct bgp_proto *p = s->proto; ea_list *attrs = NULL; @@ -1464,7 +1464,7 @@ framing_error: withdraw: /* RFC 7606 5.2 - handle missing NLRI during errors */ if (!s->ip_reach_len && !s->mp_reach_len) - bgp_parse_error(s, 1); + parse_error(s, 1); s->err_withdraw = 1; return NULL; diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 515ef2754..017677f5c 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -497,6 +497,9 @@ struct bgp_parse_state { struct bgp_channel *channel; struct linpool *pool; +, void (*parse_error)(struct bgp_parse_state *, uint); + void (*rte_update)(struct bgp_parse_state *, ...); + int as4_session; int add_path; int mpls; @@ -661,6 +664,7 @@ int bgp_encode_mp_reach_mrt(struct bgp_write_state *s, eattr *a, byte *buf, uint const char * bgp_attr_name(uint code); int bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte *end); ea_list * bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len); +int bgp_parse_update(struct bgp_parse_state *s, byte *pkt, uint len, ea_list **ea); void bgp_finish_attrs(struct bgp_parse_state *s, rta *a); void bgp_init_bucket_table(struct bgp_channel *c); diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 2eabe6ec1..b93d4a385 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -2788,9 +2788,56 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis s->cached_rta = NULL; } +int +bgp_parse_update(struct bgp_parse_state *s, byte *pkt, uint len, ea_list **ea, void (*parse_error)(struct bgp_parse_state *, uint)) +{ + /* + * UPDATE message format + * + * 2 B IPv4 Withdrawn Routes Length + * var IPv4 Withdrawn Routes NLRI + * 2 B Total Path Attribute Length + * var Path Attributes + * var IPv4 Reachable Routes NLRI + */ + log("in parse update, len %i", len); + uint pos = 0; + s->ip_unreach_len = get_u16(pkt + pos); + log("s->ip_unreach_len %i", s->ip_unreach_len); + s->ip_unreach_nlri = pkt + pos + 2; + pos += 2 + s->ip_unreach_len; + + if (pos + 2 > len) + { + parse_error(s, 1); + return 0; + } + + s->attr_len = get_u16(pkt + pos); + log("s->attr_len %i", s->attr_len); + s->attrs = pkt + pos + 2; + pos += 2 + s->attr_len; + + if (pos > len) + { + parse_error(s, 1); + return 0; + } + + s->ip_reach_len = len - pos; + s->ip_reach_nlri = pkt + pos; + + if (s->attr_len) + *ea = bgp_decode_attrs(s, s->attrs, s->attr_len, parse_error); + else + *ea = NULL; + return 1; +} + static void bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len) { + log("bgp_rx_update"); struct bgp_proto *p = conn->bgp; ea_list *ea = NULL; @@ -2828,40 +2875,8 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len) if (len < 23) { bgp_error(conn, 1, 2, pkt+16, 2); return; } - /* Skip fixed header */ - uint pos = 19; - - /* - * UPDATE message format - * - * 2 B IPv4 Withdrawn Routes Length - * var IPv4 Withdrawn Routes NLRI - * 2 B Total Path Attribute Length - * var Path Attributes - * var IPv4 Reachable Routes NLRI - */ - - s.ip_unreach_len = get_u16(pkt + pos); - s.ip_unreach_nlri = pkt + pos + 2; - pos += 2 + s.ip_unreach_len; - - if (pos + 2 > len) - bgp_parse_error(&s, 1); - - s.attr_len = get_u16(pkt + pos); - s.attrs = pkt + pos + 2; - pos += 2 + s.attr_len; - - if (pos > len) - bgp_parse_error(&s, 1); - - s.ip_reach_len = len - pos; - s.ip_reach_nlri = pkt + pos; - - if (s.attr_len) - ea = bgp_decode_attrs(&s, s.attrs, s.attr_len); - else - ea = NULL; + bgp_parse_update(&s, pkt + 19, len - 19, &ea, bgp_parse_error); /* add 19 to skip fixed header */ + log("yay update parsed"); /* Check for End-of-RIB marker */ if (!s.attr_len && !s.ip_unreach_len && !s.ip_reach_len) @@ -3489,9 +3504,11 @@ bgp_rx_packet(struct bgp_conn *conn, byte *pkt, uint len) byte type = pkt[18]; DBG("BGP: Got packet %02x (%d bytes)\n", type, len); + log("BGP: Got packet %02x (%d bytes) !!!!!!!!!!!!!!!!!!\n", type, len); conn->bgp->stats.rx_messages++; conn->bgp->stats.rx_bytes += len; + log("do we want to do mrt dump ? conn->bgp->p.mrtdump %x & MD_MESSAGES %x", conn->bgp->p.mrtdump, MD_MESSAGES); if (conn->bgp->p.mrtdump & MD_MESSAGES) bgp_dump_message(conn, pkt, len); diff --git a/proto/mrt/Makefile b/proto/mrt/Makefile index 8cd44ac18..a78f11a5a 100644 --- a/proto/mrt/Makefile +++ b/proto/mrt/Makefile @@ -1,4 +1,4 @@ -src := mrt.c +src := mrt.c mrt_parse.c obj := $(src-o-files) $(all-daemon) $(cf-local) diff --git a/proto/mrt/mrt.c b/proto/mrt/mrt.c index 1336837a8..3369c9de9 100644 --- a/proto/mrt/mrt.c +++ b/proto/mrt/mrt.c @@ -710,6 +710,10 @@ mrt_dump_cont(struct cli *c) cli_printf(c, 0, ""); mrt_table_dump_free(c->rover); c->cont = c->cleanup = c->rover = NULL; + mrt_load("mrt_dump.txt"); + log("____________________________"); + mrt_load("dump.mrt"); + mrt_load("dump_bgp.mrt"); } static void @@ -796,6 +800,7 @@ mrt_bgp_header(buffer *b, struct mrt_bgp_data *d) void mrt_dump_bgp_message(struct mrt_bgp_data *d) { + log("mrt_dump_bgp_message"); const u16 subtypes[] = { MRT_BGP4MP_MESSAGE, MRT_BGP4MP_MESSAGE_AS4, MRT_BGP4MP_MESSAGE_LOCAL, MRT_BGP4MP_MESSAGE_AS4_LOCAL, diff --git a/proto/mrt/mrt.h b/proto/mrt/mrt.h index 4ff94c120..9371ce16c 100644 --- a/proto/mrt/mrt.h +++ b/proto/mrt/mrt.h @@ -16,6 +16,7 @@ #include "nest/route.h" #include "lib/event.h" #include "lib/hash.h" +#include "proto/bgp/bgp.h" struct mrt_config { @@ -155,4 +156,6 @@ static inline void mrt_dump_bgp_message(struct mrt_bgp_data *d UNUSED) { } static inline void mrt_dump_bgp_state_change(struct mrt_bgp_data *d UNUSED) { } #endif +void mrt_load(char *file); + #endif /* _BIRD_MRT_H_ */ diff --git a/proto/mrt/mrt_parse.c b/proto/mrt/mrt_parse.c new file mode 100644 index 000000000..e7f2b45e1 --- /dev/null +++ b/proto/mrt/mrt_parse.c @@ -0,0 +1,387 @@ + +#include "mrt.h" +#include + + +byte +mrt_load_one(FILE *fp, u64 *remains) +{ + remains[0]--; + return fgetc(fp); +} + +void +mrt_load_n_octet(FILE *fp, u64 *remains, byte *buff, int n) +{ + for (int i = 0; i < n; i++) + buff[i] = fgetc(fp); + remains[0] = remains[0] - n; +} + +u64 +mrt_load_four_octet(FILE *fp, u64 *remains) +{ + u64 ret = 0; + for (int i = 0; i < 4; i++) + { + ret = ret << 8; + ret += fgetc(fp); + } + remains[0] = remains[0] - 4; + return ret; +} + +void +mrt_load_ip(FILE *fp, u64 *remains, ip_addr *addr, bool is_ip6) +{ + if (is_ip6) + for (int i = 0; i < 4; i++) + addr->addr[i] = mrt_load_four_octet(fp, remains); + else + { + addr->addr[0] = addr->addr[1] = addr->addr[2] = 0; + addr->addr[3] = mrt_load_four_octet(fp, remains); + } +} + +u32 +mrt_load_two_octet(FILE *fp, u64 *remains) +{ + remains[0] = remains[0] - 2; + return (fgetc(fp) << 8) + fgetc(fp); +} + +/* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Peer Type | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Peer BGP ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Peer IP Address (variable) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Peer AS (variable) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 6: Peer Entries +*/ + +void +mrt_parse_peer(FILE *fp, u64 *remains) +{ + int peer_type = mrt_load_one(fp, remains); + u64 peer_bgp_id = mrt_load_four_octet(fp, remains); + ip_addr addr; + u64 peer_as; + mrt_load_ip(fp, remains, &addr, peer_type & MRT_PEER_TYPE_IPV6); + + if (peer_type & MRT_PEER_TYPE_32BIT_ASN) + peer_as = mrt_load_four_octet(fp,remains); + else + peer_as = mrt_load_two_octet(fp, remains); + log("peer type %i, bgp id %li adddr %I as %li", peer_type, peer_bgp_id, addr, peer_as); +} + +/* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Collector BGP ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | View Name Length | View Name (variable) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Peer Count | Peer Entries (variable) + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 5: PEER_INDEX_TABLE Subtype +*/ + +void +mrt_parse_peer_index_table(FILE *fp, u64 *remains) +{ + u64 collector = mrt_load_four_octet(fp, remains); + int name_len = mrt_load_two_octet(fp, remains); + log("name len %i collector %lx", name_len, collector); + char name[name_len + 1]; + name[name_len] = 0; + mrt_load_n_octet(fp, remains, name, name_len); + int peer_count = mrt_load_two_octet(fp, remains); + log("name %s, count %i", name, peer_count); + + for (int i = 0; i < peer_count; i++) + mrt_parse_peer(fp, remains); +} + +/* +0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Peer Index | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Originated Time | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Attribute Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | BGP Attributes... (variable) + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +void +mrt_parse_rib_entry(FILE *fp, u64 *remains, bool add_path) +{ + int peer_index = mrt_load_two_octet(fp, remains); + u64 orig_time = mrt_load_four_octet(fp, remains); + u64 path_id; + + if (add_path) + path_id = mrt_load_four_octet(fp, remains); + + int attr_len = mrt_load_two_octet(fp, remains); + log("rib entry index %lx, time %lx, attr len %i (rem %li) path %li", peer_index, orig_time, attr_len, *remains, path_id); + //TODO how are encoded the attrs? + remains[0] = remains[0] - attr_len; + + for (int i = 0; i < attr_len; i++) + fgetc(fp); +} + + +void +mrt_parse_rib_generic(FILE *fp, u64 *remains) +{ + u64 seq_num = mrt_load_four_octet(fp, remains); + int addr_fam_id = mrt_load_two_octet(fp, remains); + int subs_afi = mrt_load_one(fp, remains); + log("seq num %lx, fam %i, subs %i", seq_num, addr_fam_id, subs_afi); + //TODO length of Network layer reachebility +} + + +/* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Sequence Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Prefix Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Prefix (variable) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Entry Count | RIB Entries (variable) + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ +void +mrt_parse_rib4_unicast(FILE *fp, u64 *remains, bool add_path) +{ + u64 seq_num = mrt_load_four_octet(fp, remains); + int pref_len = mrt_load_one(fp, remains); + byte prefix[pref_len/8]; + mrt_load_n_octet(fp, remains, prefix, pref_len/8); + int entry_count = mrt_load_two_octet(fp, remains); + log("seq %lx, pref len %i, enties %i", seq_num, pref_len, entry_count); + + for (int i = 0; i < entry_count; i++) + mrt_parse_rib_entry(fp, remains, add_path); +} + + +void +mrt_parse_error(struct bgp_parse_state * UNUSED, uint UNUSED) +{ + log("run into a parsing error"); +} + +/* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Peer AS Number | Local AS Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Interface Index | Address Family | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Peer IP Address (variable) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Local IP Address (variable) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | BGP Message... (variable) + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure 12: BGP4MP_MESSAGE Subtype +*/ +void +mrt_parse_bgp_message(FILE *fp, u64 *remains, bool as4) +{ + u64 peer_as, local_as; + if (as4) + { + peer_as = mrt_load_four_octet(fp, remains); + local_as = mrt_load_four_octet(fp, remains); + } else + { + peer_as = mrt_load_two_octet(fp, remains); + local_as = mrt_load_two_octet(fp, remains); + } + + int interface_id = mrt_load_two_octet(fp, remains); + int addr_fam = mrt_load_two_octet(fp, remains); + + ip_addr peer_addr, local_addr; + mrt_load_ip(fp, remains, &peer_addr, addr_fam == 2); + mrt_load_ip(fp, remains, &local_addr, addr_fam == 2); + + log("peer as %lx local as %lx interface %x add fam %i peer %I loc %I", peer_as, local_as, interface_id, addr_fam, peer_addr, local_addr); +} + + +void +mrt_parse_bgp4mp_message(FILE *fp, u64 *remains, bool as4) +{ + log("hereeeee bgp message"); + mrt_parse_bgp_message(fp, remains, as4); + + if (*remains < 23) + { + log(L_WARN "MRT parse BGP message: BGP message is too short (%i)", *remains); + return; + } + + for (int i = 0; i < 16; i++) // marker + fgetc(fp); + + remains[0] = remains[0] - 16; + int length = mrt_load_two_octet(fp, remains); + int type = mrt_load_one(fp, remains); + log("message type %i", type); + + if (type != PKT_UPDATE) + { + log("Another BGP type"); + return; + } + + struct bgp_parse_state s = { + .pool = lp_new(&root_pool), + }; + byte buf[length]; + mrt_load_n_octet(fp, remains, buf, length); + ea_list *ea = NULL; + log("try to parse bgp update"); + bgp_parse_update(&s, buf, length, &ea, bgp_parse_error); + log("ok, seems parsed?"); +} + + +void +mrt_parse_bgp4mp_change_state(FILE *fp, u64 *remains, bool as4) +{ + mrt_parse_bgp_message(fp, remains, as4); + int old_state = mrt_load_two_octet(fp, remains); + int new_state = mrt_load_two_octet(fp, remains); + log("old state %i new state %i", old_state, new_state); +} + + +int +mrt_parse_general_header(FILE *fp) +{ + char is_eof = fgetc(fp); + u64 timestamp = is_eof; + + if (is_eof == EOF) + return 0; + else + { + for (int i = 0; i < 3; i++) + { + log("t %lx", timestamp); + timestamp = timestamp << 8; + timestamp += fgetc(fp); + } + } + + log("timestamp is %lx", timestamp); + int type = (fgetc(fp) << 8) + fgetc(fp); + int subtype = (fgetc(fp) << 8) + fgetc(fp); + log("type is %i, subtype %x", type, subtype); + u64 length = 0; + + for (int i = 0; i < 4; i++) + { + length = length << 8; + length += fgetc(fp); + } + u64 remains = length; + log("remains is %li", remains); + + if (type == MRT_TABLE_DUMP_V2) + { + switch (subtype) + { + case (MRT_PEER_INDEX_TABLE): + mrt_parse_peer_index_table(fp, &remains); + break; + case (MRT_RIB_IPV4_UNICAST): + case (MRT_RIB_IPV6_UNICAST): + case (MRT_RIB_IPV4_MULTICAST): + case (MRT_RIB_IPV6_MULTICAST): + mrt_parse_rib4_unicast(fp, &remains, false); + break; + case (MRT_RIB_IPV4_UNICAST_ADDPATH): + case (MRT_RIB_IPV6_UNICAST_ADDPATH): + case (MRT_RIB_IPV4_MULTICAST_ADDPATH): + case (MRT_RIB_IPV6_MULTICAST_ADDPATH): + mrt_parse_rib4_unicast(fp, &remains, true); + break; + case (MRT_RIB_GENERIC): + case (MRT_RIB_GENERIC_ADDPATH): + mrt_parse_rib_generic(fp, &remains); + break; + default: + bug("mrt: unknown mrt table dump subtype"); + } + } else + { + ASSERT_DIE(type == MRT_BGP4MP); + + switch (subtype) + { + case (MRT_BGP4MP_MESSAGE): + case (MRT_BGP4MP_MESSAGE_LOCAL): + case (MRT_BGP4MP_MESSAGE_ADDPATH): + mrt_parse_bgp4mp_message(fp, &remains, false); + break; + case (MRT_BGP4MP_STATE_CHANGE_AS4): + mrt_parse_bgp4mp_change_state(fp, &remains, true); + break; + case (MRT_BGP4MP_MESSAGE_AS4): + case (MRT_BGP4MP_MESSAGE_AS4_LOCAL): + case (MRT_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH): + case (MRT_BGP4MP_MESSAGE_AS4_ADDPATH): + mrt_parse_bgp4mp_message(fp, &remains, true); + break; + } + } + + ASSERT_DIE(remains < length); + + for (u64 i = 0; i < remains; i++) + fgetc(fp); + + return 1; +} + + +void +mrt_load(char *file) +{ + FILE *fp = fopen(file, "r"); + + if (fp == NULL) + { + log(L_WARN "Can not open file %s", fp); + return; + } + + while (mrt_parse_general_header(fp)); +}