Implement the missing bits to parse the other MRT message types.
authorclaudio <claudio@openbsd.org>
Sat, 24 Oct 2015 11:54:50 +0000 (11:54 +0000)
committerclaudio <claudio@openbsd.org>
Sat, 24 Oct 2015 11:54:50 +0000 (11:54 +0000)
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.

usr.sbin/bgpctl/bgpctl.c
usr.sbin/bgpctl/mrtparser.c

index 0eee0a2..d779f77 100644 (file)
@@ -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 <henning@openbsd.org>
@@ -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, ...)
 {
index d8f7cb8..ed6fac4 100644 (file)
@@ -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 <claudio@openbsd.org>
  *
@@ -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);
+}