From: claudio Date: Sat, 24 Oct 2015 11:54:50 +0000 (+0000) Subject: Implement the missing bits to parse the other MRT message types. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=e86c4bdecf2c603db1d8f39e2d782e305be05c35;p=openbsd Implement the missing bits to parse the other MRT message types. Printing bgp messages is still missing lots but at least it is a start. I onced abused tcpdump's bgp protocol handler for this but that is an ugly hack. --- diff --git a/usr.sbin/bgpctl/bgpctl.c b/usr.sbin/bgpctl/bgpctl.c index 0eee0a27bce..d779f772fc3 100644 --- a/usr.sbin/bgpctl/bgpctl.c +++ b/usr.sbin/bgpctl/bgpctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpctl.c,v 1.184 2015/10/24 11:41:03 claudio Exp $ */ +/* $OpenBSD: bgpctl.c,v 1.185 2015/10/24 11:54:50 claudio Exp $ */ /* * Copyright (c) 2003 Henning Brauer @@ -86,13 +86,14 @@ void show_ext_community(u_char *, u_int16_t); char *fmt_mem(int64_t); int show_rib_memory_msg(struct imsg *); void send_filterset(struct imsgbuf *, struct filter_set_head *); -static const char *get_errstr(u_int8_t, u_int8_t); +const char *get_errstr(u_int8_t, u_int8_t); int show_result(struct imsg *); void show_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *); void network_mrt_dump(struct mrt_rib *, struct mrt_peer *, void *); void show_mrt_state(struct mrt_bgp_state *, void *); void show_mrt_msg(struct mrt_bgp_msg *, void *); void mrt_to_bgpd_addr(union mrt_addr *, struct bgpd_addr *); +const char *msg_type(u_int8_t); void network_bulk(struct parse_result *); const char *print_auth_method(enum auth_method); @@ -1615,7 +1616,7 @@ send_filterset(struct imsgbuf *i, struct filter_set_head *set) } } -static const char * +const char * get_errstr(u_int8_t errcode, u_int8_t subcode) { static const char *errstr = NULL; @@ -1876,13 +1877,24 @@ network_mrt_dump(struct mrt_rib *mr, struct mrt_peer *mp, void *arg) void show_mrt_state(struct mrt_bgp_state *ms, void *arg) { - printf("show_mrt_state\n"); + struct bgpd_addr src, dst; + + mrt_to_bgpd_addr(&ms->src, &src); + mrt_to_bgpd_addr(&ms->dst, &dst); + printf("%s[%u] -> ", log_addr(&src), ms->src_as); + printf("%s[%u]: %s -> %s\n", log_addr(&dst), ms->dst_as, + statenames[ms->old_state], statenames[ms->new_state]); } void show_mrt_msg(struct mrt_bgp_msg *mm, void *arg) { - printf("show_mrt_msg\n"); + struct bgpd_addr src, dst; + + mrt_to_bgpd_addr(&mm->src, &src); + mrt_to_bgpd_addr(&mm->dst, &dst); + printf("%s[%u] -> ", log_addr(&src), mm->src_as); + printf("%s[%u]: size %u\n", log_addr(&dst), mm->dst_as, mm->msg_len); } void @@ -1904,7 +1916,15 @@ mrt_to_bgpd_addr(union mrt_addr *ma, struct bgpd_addr *ba) } } -/* following functions are necessary for imsg framework */ +const char * +msg_type(u_int8_t type) +{ + if (type >= sizeof(msgtypenames)/sizeof(msgtypenames[0])) + return "BAD"; + return (msgtypenames[type]); +} + +/* following functions are necessary for the imsg framework */ void log_warnx(const char *emsg, ...) { diff --git a/usr.sbin/bgpctl/mrtparser.c b/usr.sbin/bgpctl/mrtparser.c index d8f7cb8e89b..ed6fac41ad9 100644 --- a/usr.sbin/bgpctl/mrtparser.c +++ b/usr.sbin/bgpctl/mrtparser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mrtparser.c,v 1.6 2015/01/09 08:09:39 henning Exp $ */ +/* $OpenBSD: mrtparser.c,v 1.7 2015/10/24 11:54:50 claudio Exp $ */ /* * Copyright (c) 2011 Claudio Jeker * @@ -48,6 +48,9 @@ void mrt_free_bgp_msg(struct mrt_bgp_msg *); u_char *mrt_aspath_inflate(void *, u_int16_t, u_int16_t *); int mrt_extract_addr(void *, u_int, union mrt_addr *, sa_family_t); +struct mrt_bgp_state *mrt_parse_state(struct mrt_hdr *, void *); +struct mrt_bgp_msg *mrt_parse_msg(struct mrt_hdr *, void *); + void * mrt_read_msg(int fd, struct mrt_hdr *hdr) { @@ -91,10 +94,12 @@ mrt_read_buf(int fd, void *buf, size_t len) void mrt_parse(int fd, struct mrt_parser *p, int verbose) { - struct mrt_hdr h; - struct mrt_peer *pctx = NULL; - struct mrt_rib *r; - void *msg; + struct mrt_hdr h; + struct mrt_peer *pctx = NULL; + struct mrt_rib *r; + struct mrt_bgp_state *s; + struct mrt_bgp_msg *m; + void *msg; while ((msg = mrt_read_msg(fd, &h))) { switch (ntohs(h.type)) { @@ -129,7 +134,8 @@ mrt_parse(int fd, struct mrt_parser *p, int verbose) if (p->dump == NULL) break; if (mrt_parse_dump(&h, msg, &pctx, &r) == 0) { - p->dump(r, pctx, p->arg); + if (p->dump) + p->dump(r, pctx, p->arg); mrt_free_rib(r); } break; @@ -158,7 +164,8 @@ mrt_parse(int fd, struct mrt_parser *p, int verbose) break; r = mrt_parse_v2_rib(&h, msg); if (r) { - p->dump(r, pctx, p->arg); + if (p->dump) + p->dump(r, pctx, p->arg); mrt_free_rib(r); } break; @@ -174,22 +181,30 @@ mrt_parse(int fd, struct mrt_parser *p, int verbose) switch (ntohs(h.subtype)) { case BGP4MP_STATE_CHANGE: case BGP4MP_STATE_CHANGE_AS4: - /* XXX p->state(s, p->arg); */ - errx(1, "BGP4MP subtype not yet implemented"); + if ((s = mrt_parse_state(&h, msg))) { + if (p->state) + p->state(s, p->arg); + free(s); + } break; case BGP4MP_MESSAGE: case BGP4MP_MESSAGE_AS4: case BGP4MP_MESSAGE_LOCAL: case BGP4MP_MESSAGE_AS4_LOCAL: - /* XXX p->message(m, p->arg); */ - errx(1, "BGP4MP subtype not yet implemented"); + if ((m = mrt_parse_msg(&h, msg))) { + if (p->message) + p->message(m, p->arg); + free(m->msg); + free(m); + } break; case BGP4MP_ENTRY: if (p->dump == NULL) break; if (mrt_parse_dump_mp(&h, msg, &pctx, &r) == 0) { - p->dump(r, pctx, p->arg); + if (p->dump) + p->dump(r, pctx, p->arg); mrt_free_rib(r); } break; @@ -972,3 +987,208 @@ mrt_extract_addr(void *msg, u_int len, union mrt_addr *addr, sa_family_t af) return (-1); } } + +struct mrt_bgp_state * +mrt_parse_state(struct mrt_hdr *hdr, void *msg) +{ + struct mrt_bgp_state *s; + u_int8_t *b = msg; + u_int len = ntohl(hdr->length); + u_int32_t sas, das; + u_int16_t tmp16, afi; + int r; + sa_family_t af; + + switch (ntohs(hdr->subtype)) { + case BGP4MP_STATE_CHANGE: + if (len < 8) + return (0); + /* source as */ + memcpy(&tmp16, b, sizeof(tmp16)); + b += sizeof(tmp16); + len -= sizeof(tmp16); + sas = ntohs(tmp16); + /* dest as */ + memcpy(&tmp16, b, sizeof(tmp16)); + b += sizeof(tmp16); + len -= sizeof(tmp16); + das = ntohs(tmp16); + /* if_index, ignored */ + b += sizeof(tmp16); + len -= sizeof(tmp16); + /* afi */ + memcpy(&tmp16, b, sizeof(tmp16)); + b += sizeof(tmp16); + len -= sizeof(tmp16); + afi = ntohs(tmp16); + break; + case BGP4MP_STATE_CHANGE_AS4: + if (len < 12) + return (0); + /* source as */ + memcpy(&sas, b, sizeof(sas)); + b += sizeof(sas); + len -= sizeof(sas); + sas = ntohl(sas); + /* dest as */ + memcpy(&das, b, sizeof(das)); + b += sizeof(das); + len -= sizeof(das); + das = ntohl(das); + /* if_index, ignored */ + b += sizeof(tmp16); + len -= sizeof(tmp16); + /* afi */ + memcpy(&tmp16, b, sizeof(tmp16)); + b += sizeof(tmp16); + len -= sizeof(tmp16); + afi = ntohs(tmp16); + break; + default: + errx(1, "mrt_parse_state: bad subtype"); + } + + /* src & dst addr */ + switch (afi) { + case MRT_DUMP_AFI_IP: + af = AF_INET; + break; + case MRT_DUMP_AFI_IPv6: + af = AF_INET6; + break; + default: + errx(1, "mrt_parse_state: bad afi"); + } + + if ((s = calloc(1, sizeof(struct mrt_bgp_state))) == NULL) + err(1, "calloc"); + s->src_as = sas; + s->dst_as = das; + + if ((r = mrt_extract_addr(b, len, &s->src, af)) == -1) + goto fail; + b += r; + len -= r; + if ((r = mrt_extract_addr(b, len, &s->dst, af)) == -1) + goto fail; + b += r; + len -= r; + + /* states */ + memcpy(&tmp16, b, sizeof(tmp16)); + b += sizeof(tmp16); + len -= sizeof(tmp16); + s->old_state = ntohs(tmp16); + memcpy(&tmp16, b, sizeof(tmp16)); + b += sizeof(tmp16); + len -= sizeof(tmp16); + s->new_state = ntohs(tmp16); + + return (s); + +fail: + free(s); + return (NULL); +} + +struct mrt_bgp_msg * +mrt_parse_msg(struct mrt_hdr *hdr, void *msg) +{ + struct mrt_bgp_msg *m; + u_int8_t *b = msg; + u_int len = ntohl(hdr->length); + u_int32_t sas, das; + u_int16_t tmp16, afi; + int r; + sa_family_t af; + + switch (ntohs(hdr->subtype)) { + case BGP4MP_MESSAGE: + if (len < 8) + return (0); + /* source as */ + memcpy(&tmp16, b, sizeof(tmp16)); + b += sizeof(tmp16); + len -= sizeof(tmp16); + sas = ntohs(tmp16); + /* dest as */ + memcpy(&tmp16, b, sizeof(tmp16)); + b += sizeof(tmp16); + len -= sizeof(tmp16); + das = ntohs(tmp16); + /* if_index, ignored */ + b += sizeof(tmp16); + len -= sizeof(tmp16); + /* afi */ + memcpy(&tmp16, b, sizeof(tmp16)); + b += sizeof(tmp16); + len -= sizeof(tmp16); + afi = ntohs(tmp16); + break; + case BGP4MP_MESSAGE_AS4: + if (len < 12) + return (0); + /* source as */ + memcpy(&sas, b, sizeof(sas)); + b += sizeof(sas); + len -= sizeof(sas); + sas = ntohl(sas); + /* dest as */ + memcpy(&das, b, sizeof(das)); + b += sizeof(das); + len -= sizeof(das); + das = ntohl(das); + /* if_index, ignored */ + b += sizeof(tmp16); + len -= sizeof(tmp16); + /* afi */ + memcpy(&tmp16, b, sizeof(tmp16)); + b += sizeof(tmp16); + len -= sizeof(tmp16); + afi = ntohs(tmp16); + break; + default: + errx(1, "mrt_parse_msg: bad subtype"); + } + + /* src & dst addr */ + switch (afi) { + case MRT_DUMP_AFI_IP: + af = AF_INET; + break; + case MRT_DUMP_AFI_IPv6: + af = AF_INET6; + break; + default: + errx(1, "mrt_parse_msg: bad afi"); + } + + if ((m = calloc(1, sizeof(struct mrt_bgp_msg))) == NULL) + err(1, "calloc"); + m->src_as = sas; + m->dst_as = das; + + if ((r = mrt_extract_addr(b, len, &m->src, af)) == -1) + goto fail; + b += r; + len -= r; + if ((r = mrt_extract_addr(b, len, &m->dst, af)) == -1) + goto fail; + b += r; + len -= r; + + /* msg */ + if (len > 0) { + m->msg_len = len; + if ((m->msg = malloc(len)) == NULL) + err(1, "malloc"); + memcpy(m->msg, b, len); + } + + return (m); + +fail: + free(m->msg); + free(m); + return (NULL); +}