Convert the mrtparser to use ibufs in many places.
authorclaudio <claudio@openbsd.org>
Thu, 1 Feb 2024 11:37:10 +0000 (11:37 +0000)
committerclaudio <claudio@openbsd.org>
Thu, 1 Feb 2024 11:37:10 +0000 (11:37 +0000)
More is possible but for now this covers most of the message parsers.
OK tb@

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

index 35ec608..bea30af 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: bgpctl.c,v 1.304 2024/01/31 11:23:19 claudio Exp $ */
+/*     $OpenBSD: bgpctl.c,v 1.305 2024/02/01 11:37:10 claudio Exp $ */
 
 /*
  * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
@@ -1411,24 +1411,19 @@ show_mrt_state(struct mrt_bgp_state *ms, void *arg)
 }
 
 static void
-print_afi(u_char *p, uint8_t len)
+print_afi(struct ibuf *b)
 {
        uint16_t afi;
        uint8_t safi, aid;
 
-       if (len != 4) {
+       if (ibuf_get_n16(b, &afi) == -1 ||      /* afi, 2 byte */
+           ibuf_skip(b, 1) == -1 ||            /* reserved, 1 byte */
+           ibuf_get_n8(b, &safi) == -1 ||      /* safi, 1 byte */
+           ibuf_size(b) != 0) {
                printf("bad length");
                return;
        }
 
-       /* afi, 2 byte */
-       memcpy(&afi, p, sizeof(afi));
-       afi = ntohs(afi);
-       p += 2;
-       /* reserved, 1 byte */
-       p += 1;
-       /* safi, 1 byte */
-       memcpy(&safi, p, sizeof(safi));
        if (afi2aid(afi, safi, &aid) == -1)
                printf("unknown afi %u safi %u", afi, safi);
        else
@@ -1436,12 +1431,14 @@ print_afi(u_char *p, uint8_t len)
 }
 
 static void
-print_capability(uint8_t capa_code, u_char *p, uint8_t len)
+print_capability(uint8_t capa_code, struct ibuf *b)
 {
+       uint32_t as;
+
        switch (capa_code) {
        case CAPA_MP:
                printf("multiprotocol capability: ");
-               print_afi(p, len);
+               print_afi(b);
                break;
        case CAPA_REFRESH:
                printf("route refresh capability");
@@ -1452,13 +1449,11 @@ print_capability(uint8_t capa_code, u_char *p, uint8_t len)
                break;
        case CAPA_AS4BYTE:
                printf("4-byte AS num capability: ");
-               if (len == 4) {
-                       uint32_t as;
-                       memcpy(&as, p, sizeof(as));
-                       as = ntohl(as);
-                       printf("AS %u", as);
-               } else
+               if (ibuf_get_n32(b, &as) == -1 ||
+                   ibuf_size(b) != 0)
                        printf("bad length");
+               else
+                       printf("AS %u", as);
                break;
        case CAPA_ADD_PATH:
                printf("add-path capability");
@@ -1468,7 +1463,8 @@ print_capability(uint8_t capa_code, u_char *p, uint8_t len)
                printf("enhanced route refresh capability");
                break;
        default:
-               printf("unknown capability %u length %u", capa_code, len);
+               printf("unknown capability %u length %zu",
+                   capa_code, ibuf_size(b));
                break;
        }
 }
@@ -1531,88 +1527,63 @@ print_notification(uint8_t errcode, uint8_t subcode)
 }
 
 static int
-show_mrt_capabilities(u_char *p, uint16_t len)
+show_mrt_capabilities(struct ibuf *b)
 {
-       uint16_t totlen = len;
        uint8_t capa_code, capa_len;
+       struct ibuf cbuf;
 
-       while (len > 2) {
-               memcpy(&capa_code, p, sizeof(capa_code));
-               p += sizeof(capa_code);
-               len -= sizeof(capa_code);
-               memcpy(&capa_len, p, sizeof(capa_len));
-               p += sizeof(capa_len);
-               len -= sizeof(capa_len);
-               if (len < capa_len) {
-                       printf("capa_len %u exceeds remaining length",
-                           capa_len);
+       while (ibuf_size(b) > 0) {
+               if (ibuf_get_n8(b, &capa_code) == -1 ||
+                   ibuf_get_n8(b, &capa_len) == -1 ||
+                   ibuf_get_ibuf(b, capa_len, &cbuf) == -1) {
+                       printf("truncated capabilities");
                        return (-1);
                }
                printf("\n        ");
-               print_capability(capa_code, p, capa_len);
-               p += capa_len;
-               len -= capa_len;
-       }
-       if (len != 0) {
-               printf("length mismatch while capability parsing");
-               return (-1);
+               print_capability(capa_code, &cbuf);
        }
-       return (totlen);
+       return (0);
 }
 
 static void
-show_mrt_open(u_char *p, uint16_t len)
+show_mrt_open(struct ibuf *b)
 {
        uint16_t short_as, holdtime;
        uint8_t version, optparamlen;
        struct in_addr bgpid;
 
        /* length check up to optparamlen already happened */
-       memcpy(&version, p, sizeof(version));
-       p += sizeof(version);
-       len -= sizeof(version);
-       memcpy(&short_as, p, sizeof(short_as));
-       p += sizeof(short_as);
-       len -= sizeof(short_as);
-       short_as = ntohs(short_as);
-       memcpy(&holdtime, p, sizeof(holdtime));
-       holdtime = ntohs(holdtime);
-       p += sizeof(holdtime);
-       len -= sizeof(holdtime);
-       memcpy(&bgpid, p, sizeof(bgpid));
-       p += sizeof(bgpid);
-       len -= sizeof(bgpid);
-       memcpy(&optparamlen, p, sizeof(optparamlen));
-       p += sizeof(optparamlen);
-       len -= sizeof(optparamlen);
+       if (ibuf_get_n8(b, &version) == -1 ||
+           ibuf_get_n16(b, &short_as) == -1 ||
+           ibuf_get_n16(b, &holdtime) == -1 ||
+           ibuf_get(b, &bgpid, sizeof(bgpid)) == -1 ||
+           ibuf_get_n8(b, &optparamlen) == -1) {
+ trunc:
+               printf("truncated message");
+               return;
+       }
 
        printf("\n    ");
        printf("Version: %d AS: %u Holdtime: %u BGP Id: %s Paramlen: %u",
            version, short_as, holdtime, inet_ntoa(bgpid), optparamlen);
-       if (optparamlen != len) {
+       if (optparamlen != ibuf_size(b)) {
+               /* XXX missing support for RFC9072 */
                printf("optional parameter length mismatch");
                return;
        }
-       while (len > 2) {
+       while (ibuf_size(b) > 0) {
                uint8_t op_type, op_len;
-               int r;
 
-               memcpy(&op_type, p, sizeof(op_type));
-               p += sizeof(op_type);
-               len -= sizeof(op_type);
-               memcpy(&op_len, p, sizeof(op_len));
-               p += sizeof(op_len);
-               len -= sizeof(op_len);
+               if (ibuf_get_n8(b, &op_type) == -1 ||
+                   ibuf_get_n8(b, &op_len) == -1)
+                       goto trunc;
 
                printf("\n    ");
                switch (op_type) {
                case OPT_PARAM_CAPABILITIES:
-                       printf("Capabilities: size %u", op_len);
-                       r = show_mrt_capabilities(p, op_len);
-                       if (r == -1)
+                       printf("Capabilities: %u bytes", op_len);
+                       if (show_mrt_capabilities(b) == -1)
                                return;
-                       p += r;
-                       len -= r;
                        break;
                case OPT_PARAM_AUTH:
                default:
@@ -1621,89 +1592,71 @@ show_mrt_open(u_char *p, uint16_t len)
                        return;
                }
        }
-       if (len != 0) {
-               printf("optional parameter encoding error");
-               return;
-       }
 }
 
 static void
-show_mrt_notification(u_char *p, uint16_t len)
+show_mrt_notification(struct ibuf *b)
 {
-       uint16_t i;
-       uint8_t errcode, subcode;
-       size_t reason_len;
        char reason[REASON_LEN];
+       uint8_t errcode, subcode, reason_len, c;
+       size_t i, len;
 
-       memcpy(&errcode, p, sizeof(errcode));
-       p += sizeof(errcode);
-       len -= sizeof(errcode);
-
-       memcpy(&subcode, p, sizeof(subcode));
-       p += sizeof(subcode);
-       len -= sizeof(subcode);
+       if (ibuf_get_n8(b, &errcode) == -1 ||
+           ibuf_get_n8(b, &subcode) == -1) {
+ trunc:
+               printf("truncated message");
+               return;
+       }
 
        printf("\n    ");
        print_notification(errcode, subcode);
 
        if (errcode == ERR_CEASE && (subcode == ERR_CEASE_ADMIN_DOWN ||
            subcode == ERR_CEASE_ADMIN_RESET)) {
-               if (len > 1) {
-                       reason_len = *p++;
-                       len--;
-                       if (len < reason_len) {
-                               printf("truncated shutdown reason");
-                               return;
-                       }
-                       if (reason_len > REASON_LEN - 1) {
-                               printf("overly long shutdown reason");
-                               return;
-                       }
-                       memcpy(reason, p, reason_len);
+               if (ibuf_size(b) > 1) {
+                       if (ibuf_get_n8(b, &reason_len) == -1)
+                               goto trunc;
+                       if (ibuf_get(b, reason, reason_len) == -1)
+                               goto trunc;
                        reason[reason_len] = '\0';
                        printf("shutdown reason: \"%s\"",
                            log_reason(reason));
-                       p += reason_len;
-                       len -= reason_len;
                }
        }
        if (errcode == ERR_OPEN && subcode == ERR_OPEN_CAPA) {
-               int r;
-
-               r = show_mrt_capabilities(p, len);
-               if (r == -1)
+               if (show_mrt_capabilities(b) == -1)
                        return;
-               p += r;
-               len -= r;
        }
 
-       if (len > 0) {
-               printf("\n    additional data %u bytes", len);
+       if (ibuf_size(b) > 0) {
+               len = ibuf_size(b);
+               printf("\n    additional data, %zu bytes", len);
                for (i = 0; i < len; i++) {
                        if (i % 16 == 0)
                                printf("\n    ");
                        if (i % 8 == 0)
                                printf("   ");
-                       printf(" %02X", *p++);
+                       if (ibuf_get_n8(b, &c) == -1)
+                               goto trunc;
+                       printf(" %02X", c);
                }
        }
 }
 
 /* XXX this function does not handle JSON output */
 static void
-show_mrt_update(u_char *p, uint16_t len, int reqflags, int addpath)
+show_mrt_update(struct ibuf *b, int reqflags, int addpath)
 {
        struct bgpd_addr prefix;
-       struct ibuf *b, buf, wbuf, abuf;
+       struct ibuf wbuf, abuf;
        uint32_t pathid;
        uint16_t wlen, alen;
        uint8_t prefixlen;
 
-       ibuf_from_buffer(&buf, p, len);
-       b = &buf;
        if (ibuf_get_n16(b, &wlen) == -1 ||
            ibuf_get_ibuf(b, wlen, &wbuf) == -1)
                goto trunc;
+
        if (wlen > 0) {
                printf("\n     Withdrawn prefixes:");
                while (ibuf_size(&wbuf) > 0) {
@@ -1780,35 +1733,34 @@ show_mrt_msg(struct mrt_bgp_msg *mm, void *arg)
        static const uint8_t marker[MSGSIZE_HEADER_MARKER] = {
            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-       u_char *p;
+       uint8_t m[MSGSIZE_HEADER_MARKER];
+       struct ibuf *b;
        uint16_t len;
        uint8_t type;
        struct ctl_show_rib_request *req = arg;
 
        printf("%s %s[%u] -> ", fmt_time(&mm->time),
            log_addr(&mm->src), mm->src_as);
-       printf("%s[%u]: size %u%s ", log_addr(&mm->dst), mm->dst_as,
-           mm->msg_len, mm->add_path ? " addpath" : "");
-       p = mm->msg;
-       len = mm->msg_len;
+       printf("%s[%u]: size %zu%s ", log_addr(&mm->dst), mm->dst_as,
+           ibuf_size(&mm->msg), mm->add_path ? " addpath" : "");
+       b = &mm->msg;
 
-       if (len < MSGSIZE_HEADER) {
-               printf("illegal header length: %u byte\n", len);
+       if (ibuf_get(b, m, sizeof(m)) == -1) {
+               printf("bad message: short header\n");
                return;
        }
 
        /* parse BGP message header */
-       if (memcmp(p, marker, sizeof(marker))) {
+       if (memcmp(m, marker, sizeof(marker))) {
                printf("incorrect marker in BGP message\n");
                return;
        }
-       p += MSGSIZE_HEADER_MARKER;
 
-       memcpy(&len, p, 2);
-       len = ntohs(len);
-       p += 2;
-       memcpy(&type, p, 1);
-       p += 1;
+       if (ibuf_get_n16(b, &len) == -1 ||
+           ibuf_get_n8(b, &type) == -1) {
+               printf("bad message: short header\n");
+               return;
+       }
 
        if (len < MSGSIZE_HEADER || len > MAX_PKTSIZE) {
                printf("illegal header length: %u byte\n", len);
@@ -1819,32 +1771,31 @@ show_mrt_msg(struct mrt_bgp_msg *mm, void *arg)
        case OPEN:
                printf("%s ", msgtypenames[type]);
                if (len < MSGSIZE_OPEN_MIN) {
-                       printf("illegal length: %u byte\n", len);
+                       printf("bad length: %u bytes\n", len);
                        return;
                }
-               show_mrt_open(p, len - MSGSIZE_HEADER);
+               show_mrt_open(b);
                break;
        case NOTIFICATION:
                printf("%s ", msgtypenames[type]);
                if (len < MSGSIZE_NOTIFICATION_MIN) {
-                       printf("illegal length: %u byte\n", len);
+                       printf("bad length: %u bytes\n", len);
                        return;
                }
-               show_mrt_notification(p, len - MSGSIZE_HEADER);
+               show_mrt_notification(b);
                break;
        case UPDATE:
                printf("%s ", msgtypenames[type]);
                if (len < MSGSIZE_UPDATE_MIN) {
-                       printf("illegal length: %u byte\n", len);
+                       printf("bad length: %u bytes\n", len);
                        return;
                }
-               show_mrt_update(p, len - MSGSIZE_HEADER, req->flags,
-                   mm->add_path);
+               show_mrt_update(b, req->flags, mm->add_path);
                break;
        case KEEPALIVE:
                printf("%s ", msgtypenames[type]);
                if (len != MSGSIZE_KEEPALIVE) {
-                       printf("illegal length: %u byte\n", len);
+                       printf("bad length: %u bytes\n", len);
                        return;
                }
                /* nothing */
@@ -1852,10 +1803,10 @@ show_mrt_msg(struct mrt_bgp_msg *mm, void *arg)
        case RREFRESH:
                printf("%s ", msgtypenames[type]);
                if (len != MSGSIZE_RREFRESH) {
-                       printf("illegal length: %u byte\n", len);
+                       printf("bad length: %u bytes\n", len);
                        return;
                }
-               print_afi(p, len);
+               print_afi(b);
                break;
        default:
                printf("unknown type %u\n", type);
index 35c1b60..a2a1a86 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mrtparser.c,v 1.21 2024/01/23 16:16:15 claudio Exp $ */
+/*     $OpenBSD: mrtparser.c,v 1.22 2024/02/01 11:37:10 claudio Exp $ */
 /*
  * Copyright (c) 2011 Claudio Jeker <claudio@openbsd.org>
  *
 #include "mrt.h"
 #include "mrtparser.h"
 
-void   *mrt_read_msg(int, struct mrt_hdr *);
-size_t  mrt_read_buf(int, void *, size_t);
-
-struct mrt_peer        *mrt_parse_v2_peer(struct mrt_hdr *, void *);
-struct mrt_rib *mrt_parse_v2_rib(struct mrt_hdr *, void *, int);
-int    mrt_parse_dump(struct mrt_hdr *, void *, struct mrt_peer **,
+struct mrt_peer        *mrt_parse_v2_peer(struct mrt_hdr *, struct ibuf *);
+struct mrt_rib *mrt_parse_v2_rib(struct mrt_hdr *, struct ibuf *, int);
+int    mrt_parse_dump(struct mrt_hdr *, struct ibuf *, struct mrt_peer **,
            struct mrt_rib **);
-int    mrt_parse_dump_mp(struct mrt_hdr *, void *, struct mrt_peer **,
+int    mrt_parse_dump_mp(struct mrt_hdr *, struct ibuf *, struct mrt_peer **,
            struct mrt_rib **, int);
-int    mrt_extract_attr(struct mrt_rib_entry *, u_char *, int, uint8_t, int);
+int    mrt_extract_attr(struct mrt_rib_entry *, struct ibuf *, uint8_t, int);
 
 void   mrt_free_peers(struct mrt_peer *);
 void   mrt_free_rib(struct mrt_rib *);
-void   mrt_free_bgp_state(struct mrt_bgp_state *);
-void   mrt_free_bgp_msg(struct mrt_bgp_msg *);
 
-u_char *mrt_aspath_inflate(void *, uint16_t, uint16_t *);
-int    mrt_extract_addr(void *, u_int, struct bgpd_addr *, uint8_t);
-int    mrt_extract_prefix(void *, u_int, uint8_t, struct bgpd_addr *,
+u_char *mrt_aspath_inflate(struct ibuf *, uint16_t *);
+int    mrt_extract_addr(struct ibuf *, struct bgpd_addr *, uint8_t);
+int    mrt_extract_prefix(struct ibuf *, uint8_t, struct bgpd_addr *,
            uint8_t *, int);
 
-struct mrt_bgp_state   *mrt_parse_state(struct mrt_hdr *, void *, int);
-struct mrt_bgp_msg     *mrt_parse_msg(struct mrt_hdr *, void *, int);
-
-void *
-mrt_read_msg(int fd, struct mrt_hdr *hdr)
-{
-       void *buf;
-
-       memset(hdr, 0, sizeof(*hdr));
-       if (mrt_read_buf(fd, hdr, sizeof(*hdr)) != sizeof(*hdr))
-               return (NULL);
-
-       if ((buf = malloc(ntohl(hdr->length))) == NULL)
-               err(1, "malloc(%d)", hdr->length);
+int    mrt_parse_state(struct mrt_bgp_state *, struct mrt_hdr *,
+           struct ibuf *, int);
+int    mrt_parse_msg(struct mrt_bgp_msg *, struct mrt_hdr *,
+           struct ibuf *, int);
 
-       if (mrt_read_buf(fd, buf, ntohl(hdr->length)) != ntohl(hdr->length)) {
-               free(buf);
-               return (NULL);
-       }
-       return (buf);
-}
-
-size_t
+static size_t
 mrt_read_buf(int fd, void *buf, size_t len)
 {
        char *b = buf;
@@ -93,17 +71,41 @@ mrt_read_buf(int fd, void *buf, size_t len)
        return (b - (char *)buf);
 }
 
+static struct ibuf *
+mrt_read_msg(int fd, struct mrt_hdr *hdr)
+{
+       struct ibuf *buf;
+       size_t len;
+
+       memset(hdr, 0, sizeof(*hdr));
+       if (mrt_read_buf(fd, hdr, sizeof(*hdr)) != sizeof(*hdr))
+               return (NULL);
+
+       len = ntohl(hdr->length);
+       if ((buf = ibuf_open(len)) == NULL)
+               err(1, "ibuf_open(%zu)", len);
+
+       if (mrt_read_buf(fd, ibuf_reserve(buf, len), len) != len) {
+               ibuf_free(buf);
+               return (NULL);
+       }
+       return (buf);
+}
+
 void
 mrt_parse(int fd, struct mrt_parser *p, int verbose)
 {
        struct mrt_hdr          h;
+       struct mrt_bgp_state    s;
+       struct mrt_bgp_msg      m;
        struct mrt_peer         *pctx = NULL;
        struct mrt_rib          *r;
-       struct mrt_bgp_state    *s;
-       struct mrt_bgp_msg      *m;
-       void                    *msg;
+       struct ibuf             *msg;
 
-       while ((msg = mrt_read_msg(fd, &h))) {
+       while ((msg = mrt_read_msg(fd, &h)) != NULL) {
+               if (ibuf_size(msg) != ntohl(h.length))
+                       errx(1, "corrupt message, %zu vs %u", ibuf_size(msg),
+                           ntohl(h.length));
                switch (ntohs(h.type)) {
                case MSG_NULL:
                case MSG_START:
@@ -188,10 +190,10 @@ mrt_parse(int fd, struct mrt_parser *p, int verbose)
                        switch (ntohs(h.subtype)) {
                        case BGP4MP_STATE_CHANGE:
                        case BGP4MP_STATE_CHANGE_AS4:
-                               if ((s = mrt_parse_state(&h, msg, verbose))) {
+                               if (mrt_parse_state(&s, &h, msg,
+                                   verbose) != -1) {
                                        if (p->state)
-                                               p->state(s, p->arg);
-                                       free(s);
+                                               p->state(&s, p->arg);
                                }
                                break;
                        case BGP4MP_MESSAGE:
@@ -202,11 +204,9 @@ mrt_parse(int fd, struct mrt_parser *p, int verbose)
                        case BGP4MP_MESSAGE_AS4_ADDPATH:
                        case BGP4MP_MESSAGE_LOCAL_ADDPATH:
                        case BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH:
-                               if ((m = mrt_parse_msg(&h, msg, verbose))) {
+                               if (mrt_parse_msg(&m, &h, msg, verbose) != -1) {
                                        if (p->message)
-                                               p->message(m, p->arg);
-                                       free(m->msg);
-                                       free(m);
+                                               p->message(&m, p->arg);
                                }
                                break;
                        case BGP4MP_ENTRY:
@@ -231,7 +231,7 @@ mrt_parse(int fd, struct mrt_parser *p, int verbose)
                                printf("unknown MRT type %d\n", ntohs(h.type));
                        break;
                }
-               free(msg);
+               ibuf_free(msg);
        }
        if (pctx)
                mrt_free_peers(pctx);
@@ -262,16 +262,14 @@ mrt_afi2aid(int afi, int safi, int verbose)
 }
 
 struct mrt_peer *
-mrt_parse_v2_peer(struct mrt_hdr *hdr, void *msg)
+mrt_parse_v2_peer(struct mrt_hdr *hdr, struct ibuf *msg)
 {
        struct mrt_peer_entry   *peers = NULL;
        struct mrt_peer *p;
-       uint8_t         *b = msg;
-       uint32_t        bid, as4;
-       uint16_t        cnt, i, as2;
-       u_int           len = ntohl(hdr->length);
+       uint32_t        bid;
+       uint16_t        cnt, i;
 
-       if (len < 8)    /* min msg size */
+       if (ibuf_size(msg) < 8) /* min msg size */
                return NULL;
 
        p = calloc(1, sizeof(struct mrt_peer));
@@ -279,38 +277,24 @@ mrt_parse_v2_peer(struct mrt_hdr *hdr, void *msg)
                err(1, "calloc");
 
        /* collector bgp id */
-       memcpy(&bid, b, sizeof(bid));
-       b += sizeof(bid);
-       len -= sizeof(bid);
-       p->bgp_id = ntohl(bid);
-
-       /* view name length */
-       memcpy(&cnt, b, sizeof(cnt));
-       b += sizeof(cnt);
-       len -= sizeof(cnt);
-       cnt = ntohs(cnt);
+       if (ibuf_get_n32(msg, &bid) == -1 ||
+           ibuf_get_n16(msg, &cnt) == -1)
+               goto fail;
 
        /* view name */
-       if (cnt > len)
-               goto fail;
        if (cnt != 0) {
                if ((p->view = malloc(cnt + 1)) == NULL)
                        err(1, "malloc");
-               memcpy(p->view, b, cnt);
+               if (ibuf_get(msg, p->view, cnt) == -1)
+                       goto fail;
                p->view[cnt] = 0;
        } else
                if ((p->view = strdup("")) == NULL)
                        err(1, "strdup");
-       b += cnt;
-       len -= cnt;
 
        /* peer_count */
-       if (len < sizeof(cnt))
+       if (ibuf_get_n16(msg, &cnt) == -1)
                goto fail;
-       memcpy(&cnt, b, sizeof(cnt));
-       b += sizeof(cnt);
-       len -= sizeof(cnt);
-       cnt = ntohs(cnt);
 
        /* peer entries */
        if ((peers = calloc(cnt, sizeof(struct mrt_peer_entry))) == NULL)
@@ -318,41 +302,30 @@ mrt_parse_v2_peer(struct mrt_hdr *hdr, void *msg)
        for (i = 0; i < cnt; i++) {
                uint8_t type;
 
-               if (len < sizeof(uint8_t) + sizeof(uint32_t))
+               if (ibuf_get_n8(msg, &type) == -1 ||
+                   ibuf_get_n32(msg, &peers[i].bgp_id) == -1)
                        goto fail;
-               type = *b++;
-               len -= 1;
-               memcpy(&bid, b, sizeof(bid));
-               b += sizeof(bid);
-               len -= sizeof(bid);
-               peers[i].bgp_id = ntohl(bid);
 
                if (type & MRT_DUMP_V2_PEER_BIT_I) {
-                       if (mrt_extract_addr(b, len, &peers[i].addr,
+                       if (mrt_extract_addr(msg, &peers[i].addr,
                            AID_INET6) == -1)
                                goto fail;
-                       b += sizeof(struct in6_addr);
-                       len -= sizeof(struct in6_addr);
                } else {
-                       if (mrt_extract_addr(b, len, &peers[i].addr,
+                       if (mrt_extract_addr(msg, &peers[i].addr,
                            AID_INET) == -1)
                                goto fail;
-                       b += sizeof(struct in_addr);
-                       len -= sizeof(struct in_addr);
                }
 
                if (type & MRT_DUMP_V2_PEER_BIT_A) {
-                       memcpy(&as4, b, sizeof(as4));
-                       b += sizeof(as4);
-                       len -= sizeof(as4);
-                       as4 = ntohl(as4);
+                       if (ibuf_get_n32(msg, &peers[i].asnum) == -1)
+                               goto fail;
                } else {
-                       memcpy(&as2, b, sizeof(as2));
-                       b += sizeof(as2);
-                       len -= sizeof(as2);
-                       as4 = ntohs(as2);
+                       uint16_t as2;
+
+                       if (ibuf_get_n16(msg, &as2) == -1)
+                               goto fail;
+                       peers[i].asnum = as2;
                }
-               peers[i].asnum = as4;
        }
        p->peers = peers;
        p->npeers = cnt;
@@ -364,29 +337,20 @@ fail:
 }
 
 struct mrt_rib *
-mrt_parse_v2_rib(struct mrt_hdr *hdr, void *msg, int verbose)
+mrt_parse_v2_rib(struct mrt_hdr *hdr, struct ibuf *msg, int verbose)
 {
        struct mrt_rib_entry *entries = NULL;
        struct mrt_rib  *r;
-       uint8_t         *b = msg;
-       u_int           len = ntohl(hdr->length);
-       uint32_t        snum, path_id = 0;
-       uint16_t        cnt, i, afi;
+       uint16_t        i, afi;
        uint8_t         safi, aid;
-       int             ret;
-
-       if (len < sizeof(snum) + 1)
-               return NULL;
 
        r = calloc(1, sizeof(struct mrt_rib));
        if (r == NULL)
                err(1, "calloc");
 
        /* seq_num */
-       memcpy(&snum, b, sizeof(snum));
-       b += sizeof(snum);
-       len -= sizeof(snum);
-       r->seqnum = ntohl(snum);
+       if (ibuf_get_n32(msg, &r->seqnum) == -1)
+               goto fail;
 
        switch (ntohs(hdr->subtype)) {
        case MRT_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH:
@@ -396,9 +360,8 @@ mrt_parse_v2_rib(struct mrt_hdr *hdr, void *msg, int verbose)
        case MRT_DUMP_V2_RIB_IPV4_UNICAST:
        case MRT_DUMP_V2_RIB_IPV4_MULTICAST:
                /* prefix */
-               ret = mrt_extract_prefix(b, len, AID_INET, &r->prefix,
-                   &r->prefixlen, verbose);
-               if (ret == -1)
+               if (mrt_extract_prefix(msg, AID_INET, &r->prefix,
+                   &r->prefixlen, verbose) == -1)
                        goto fail;
                break;
        case MRT_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH:
@@ -408,9 +371,8 @@ mrt_parse_v2_rib(struct mrt_hdr *hdr, void *msg, int verbose)
        case MRT_DUMP_V2_RIB_IPV6_UNICAST:
        case MRT_DUMP_V2_RIB_IPV6_MULTICAST:
                /* prefix */
-               ret = mrt_extract_prefix(b, len, AID_INET6, &r->prefix,
-                   &r->prefixlen, verbose);
-               if (ret == -1)
+               if (mrt_extract_prefix(msg, AID_INET6, &r->prefix,
+                   &r->prefixlen, verbose) == -1)
                        goto fail;
                break;
        case MRT_DUMP_V2_RIB_GENERIC_ADDPATH:
@@ -423,86 +385,58 @@ mrt_parse_v2_rib(struct mrt_hdr *hdr, void *msg, int verbose)
                /* FALLTHROUGH */
        case MRT_DUMP_V2_RIB_GENERIC:
                /* fetch AFI/SAFI pair */
-               if (len < 3)
+               if (ibuf_get_n16(msg, &afi) == -1 ||
+                   ibuf_get_n8(msg, &safi) == -1)
                        goto fail;
-               memcpy(&afi, b, sizeof(afi));
-               b += sizeof(afi);
-               len -= sizeof(afi);
-               afi = ntohs(afi);
-
-               safi = *b++;
-               len -= 1;
 
                if ((aid = mrt_afi2aid(afi, safi, verbose)) == AID_UNSPEC)
                        goto fail;
 
                /* prefix */
-               ret = mrt_extract_prefix(b, len, aid, &r->prefix,
-                   &r->prefixlen, verbose);
-               if (ret == -1)
+               if (mrt_extract_prefix(msg, aid, &r->prefix,
+                   &r->prefixlen, verbose) == -1)
                        goto fail;
                break;
        default:
                errx(1, "unknown subtype %hd", ntohs(hdr->subtype));
        }
 
-       /* adjust length */
-       b += ret;
-       len -= ret;
-
        /* entries count */
-       if (len < sizeof(cnt))
+       if (ibuf_get_n16(msg, &r->nentries) == -1)
                goto fail;
-       memcpy(&cnt, b, sizeof(cnt));
-       b += sizeof(cnt);
-       len -= sizeof(cnt);
-       cnt = ntohs(cnt);
-       r->nentries = cnt;
 
        /* entries */
-       if ((entries = calloc(cnt, sizeof(struct mrt_rib_entry))) == NULL)
+       if ((entries = calloc(r->nentries, sizeof(struct mrt_rib_entry))) ==
+           NULL)
                err(1, "calloc");
-       for (i = 0; i < cnt; i++) {
+       for (i = 0; i < r->nentries; i++) {
+               struct ibuf     abuf;
                uint32_t        otm;
-               uint16_t        pix, alen;
-               if (len < 2 * sizeof(uint16_t) + sizeof(uint32_t))
-                       goto fail;
+               uint16_t        alen;
+
                /* peer index */
-               memcpy(&pix, b, sizeof(pix));
-               b += sizeof(pix);
-               len -= sizeof(pix);
-               entries[i].peer_idx = ntohs(pix);
+               if (ibuf_get_n16(msg, &entries[i].peer_idx) == -1)
+                       goto fail;
 
                /* originated */
-               memcpy(&otm, b, sizeof(otm));
-               b += sizeof(otm);
-               len -= sizeof(otm);
-               entries[i].originated = ntohl(otm);
+               if (ibuf_get_n32(msg, &otm) == -1)
+                       goto fail;
+               entries[i].originated = otm;
 
                if (r->add_path) {
-                       if (len < sizeof(path_id) + sizeof(alen))
+                       if (ibuf_get_n32(msg, &entries[i].path_id) == -1)
                                goto fail;
-                       memcpy(&path_id, b, sizeof(path_id));
-                       b += sizeof(path_id);
-                       len -= sizeof(path_id);
-                       path_id = ntohl(path_id);
                }
-               entries[i].path_id = path_id;
 
                /* attr_len */
-               memcpy(&alen, b, sizeof(alen));
-               b += sizeof(alen);
-               len -= sizeof(alen);
-               alen = ntohs(alen);
+               if (ibuf_get_n16(msg, &alen) == -1 ||
+                   ibuf_get_ibuf(msg, alen, &abuf) == -1)
+                       goto fail;
 
                /* attr */
-               if (len < alen)
-                       goto fail;
-               if (mrt_extract_attr(&entries[i], b, alen,
-                   r->prefix.aid, 1) == -1)
+               if (mrt_extract_attr(&entries[i], &abuf, r->prefix.aid,
+                   1) == -1)
                        goto fail;
-               b += alen;
-               len -= alen;
        }
        r->entries = entries;
        return (r);
@@ -513,15 +447,15 @@ fail:
 }
 
 int
-mrt_parse_dump(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp,
+mrt_parse_dump(struct mrt_hdr *hdr, struct ibuf *msg, struct mrt_peer **pp,
     struct mrt_rib **rp)
 {
+       struct ibuf              abuf;
        struct mrt_peer         *p;
        struct mrt_rib          *r;
        struct mrt_rib_entry    *re;
-       uint8_t                 *b = msg;
-       u_int                    len = ntohl(hdr->length);
-       uint16_t                 asnum, alen;
+       uint32_t                 tmp32;
+       uint16_t                 tmp16, alen;
 
        if (*pp == NULL) {
                *pp = calloc(1, sizeof(struct mrt_peer));
@@ -543,76 +477,48 @@ mrt_parse_dump(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp,
        r->nentries = 1;
        r->entries = re;
 
-       if (len < 2 * sizeof(uint16_t))
+       if (ibuf_skip(msg, sizeof(uint16_t)) == -1 ||   /* view */
+           ibuf_get_n16(msg, &tmp16) == -1)            /* seqnum */
                goto fail;
-       /* view */
-       b += sizeof(uint16_t);
-       len -= sizeof(uint16_t);
-       /* seqnum */
-       memcpy(&r->seqnum, b, sizeof(uint16_t));
-       b += sizeof(uint16_t);
-       len -= sizeof(uint16_t);
-       r->seqnum = ntohs(r->seqnum);
+       r->seqnum = tmp16;
 
        switch (ntohs(hdr->subtype)) {
        case MRT_DUMP_AFI_IP:
-               if (mrt_extract_addr(b, len, &r->prefix, AID_INET) == -1)
+               if (mrt_extract_addr(msg, &r->prefix, AID_INET) == -1)
                        goto fail;
-               b += sizeof(struct in_addr);
-               len -= sizeof(struct in_addr);
                break;
        case MRT_DUMP_AFI_IPv6:
-               if (mrt_extract_addr(b, len, &r->prefix, AID_INET6) == -1)
+               if (mrt_extract_addr(msg, &r->prefix, AID_INET6) == -1)
                        goto fail;
-               b += sizeof(struct in6_addr);
-               len -= sizeof(struct in6_addr);
                break;
        }
-       if (len < 2 * sizeof(uint32_t) + 2 * sizeof(uint16_t) + 2)
+       if (ibuf_get_n8(msg, &r->prefixlen) == -1 ||    /* prefixlen */
+           ibuf_skip(msg, 1) == -1 ||                  /* status */
+           ibuf_get_n32(msg, &tmp32) == -1)            /* originated */
                goto fail;
-       r->prefixlen = *b++;
-       len -= 1;
-       /* status */
-       b += 1;
-       len -= 1;
-       /* originated */
-       memcpy(&re->originated, b, sizeof(uint32_t));
-       b += sizeof(uint32_t);
-       len -= sizeof(uint32_t);
-       re->originated = ntohl(re->originated);
+       re->originated = tmp32;
        /* peer ip */
        switch (ntohs(hdr->subtype)) {
        case MRT_DUMP_AFI_IP:
-               if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET) == -1)
+               if (mrt_extract_addr(msg, &p->peers->addr, AID_INET) == -1)
                        goto fail;
-               b += sizeof(struct in_addr);
-               len -= sizeof(struct in_addr);
                break;
        case MRT_DUMP_AFI_IPv6:
-               if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET6) == -1)
+               if (mrt_extract_addr(msg, &p->peers->addr, AID_INET6) == -1)
                        goto fail;
-               b += sizeof(struct in6_addr);
-               len -= sizeof(struct in6_addr);
                break;
        }
-       memcpy(&asnum, b, sizeof(asnum));
-       b += sizeof(asnum);
-       len -= sizeof(asnum);
-       p->peers->asnum = ntohs(asnum);
+       if (ibuf_get_n16(msg, &tmp16) == -1)
+               goto fail;
+       p->peers->asnum = tmp16;
 
-       memcpy(&alen, b, sizeof(alen));
-       b += sizeof(alen);
-       len -= sizeof(alen);
-       alen = ntohs(alen);
+       if (ibuf_get_n16(msg, &alen) == -1 ||
+           ibuf_get_ibuf(msg, alen, &abuf) == -1)
+               goto fail;
 
        /* attr */
-       if (len < alen)
+       if (mrt_extract_attr(re, &abuf, r->prefix.aid, 0) == -1)
                goto fail;
-       if (mrt_extract_attr(re, b, alen, r->prefix.aid, 0) == -1)
-               goto fail;
-       b += alen;
-       len -= alen;
-
        return (0);
 fail:
        mrt_free_rib(r);
@@ -620,23 +526,16 @@ fail:
 }
 
 int
-mrt_parse_dump_mp(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp,
+mrt_parse_dump_mp(struct mrt_hdr *hdr, struct ibuf *msg, struct mrt_peer **pp,
     struct mrt_rib **rp, int verbose)
 {
+       struct ibuf              abuf;
        struct mrt_peer         *p;
        struct mrt_rib          *r;
        struct mrt_rib_entry    *re;
-       uint8_t                 *b = msg;
-       u_int                    len = ntohl(hdr->length);
+       uint32_t                 tmp32;
        uint16_t                 asnum, alen, afi;
        uint8_t                  safi, nhlen, aid;
-       int                      ret;
-
-       /* just ignore the microsec field for _ET header for now */
-       if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) {
-               b = (char *)b + sizeof(uint32_t);
-               len -= sizeof(uint32_t);
-       }
 
        if (*pp == NULL) {
                *pp = calloc(1, sizeof(struct mrt_peer));
@@ -658,109 +557,68 @@ mrt_parse_dump_mp(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp,
        r->nentries = 1;
        r->entries = re;
 
-       if (len < 4 * sizeof(uint16_t))
+       /* just ignore the microsec field for _ET header for now */
+       if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) {
+               if (ibuf_skip(msg, sizeof(uint32_t)) == -1)
+                       goto fail;
+       }
+
+       if (ibuf_skip(msg, sizeof(uint16_t)) == -1 ||   /* source AS */
+           ibuf_get_n16(msg, &asnum) == -1 ||          /* dest AS */
+           ibuf_skip(msg, sizeof(uint16_t)) == -1 ||   /* iface index */
+           ibuf_get_n16(msg, &afi) == -1)
                goto fail;
-       /* source AS */
-       b += sizeof(uint16_t);
-       len -= sizeof(uint16_t);
-       /* dest AS */
-       memcpy(&asnum, b, sizeof(asnum));
-       b += sizeof(asnum);
-       len -= sizeof(asnum);
-       p->peers->asnum = ntohs(asnum);
-       /* iface index */
-       b += sizeof(uint16_t);
-       len -= sizeof(uint16_t);
-       /* afi */
-       memcpy(&afi, b, sizeof(afi));
-       b += sizeof(afi);
-       len -= sizeof(afi);
-       afi = ntohs(afi);
+       p->peers->asnum = asnum;
 
        /* source + dest ip */
        switch (afi) {
        case MRT_DUMP_AFI_IP:
-               if (len < 2 * sizeof(struct in_addr))
-                       goto fail;
                /* source IP */
-               b += sizeof(struct in_addr);
-               len -= sizeof(struct in_addr);
+               if (ibuf_skip(msg, sizeof(struct in_addr)) == -1)
+                       goto fail;
                /* dest IP */
-               if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET) == -1)
+               if (mrt_extract_addr(msg, &p->peers->addr, AID_INET) == -1)
                        goto fail;
-               b += sizeof(struct in_addr);
-               len -= sizeof(struct in_addr);
                break;
        case MRT_DUMP_AFI_IPv6:
-               if (len < 2 * sizeof(struct in6_addr))
-                       goto fail;
                /* source IP */
-               b += sizeof(struct in6_addr);
-               len -= sizeof(struct in6_addr);
+               if (ibuf_skip(msg, sizeof(struct in6_addr)) == -1)
+                       goto fail;
                /* dest IP */
-               if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET6) == -1)
+               if (mrt_extract_addr(msg, &p->peers->addr, AID_INET6) == -1)
                        goto fail;
-               b += sizeof(struct in6_addr);
-               len -= sizeof(struct in6_addr);
                break;
        }
 
-       if (len < 2 * sizeof(uint16_t) + 2 * sizeof(uint32_t))
+       if (ibuf_skip(msg, sizeof(uint16_t)) == -1 ||   /* view */
+           ibuf_skip(msg, sizeof(uint16_t)) == -1 ||   /* status */
+           ibuf_get_n32(msg, &tmp32) == -1)            /* originated */
                goto fail;
-       /* view + status */
-       b += 2 * sizeof(uint16_t);
-       len -= 2 * sizeof(uint16_t);
-       /* originated */
-       memcpy(&re->originated, b, sizeof(uint32_t));
-       b += sizeof(uint32_t);
-       len -= sizeof(uint32_t);
-       re->originated = ntohl(re->originated);
-
-       /* afi */
-       memcpy(&afi, b, sizeof(afi));
-       b += sizeof(afi);
-       len -= sizeof(afi);
-       afi = ntohs(afi);
-
-       /* safi */
-       safi = *b++;
-       len -= 1;
+       re->originated = tmp32;
 
+       if (ibuf_get_n16(msg, &afi) == -1 ||            /* afi */
+           ibuf_get_n8(msg, &safi) == -1)              /* safi */
+               goto fail;
        if ((aid = mrt_afi2aid(afi, safi, verbose)) == AID_UNSPEC)
                goto fail;
 
-       /* nhlen */
-       nhlen = *b++;
-       len -= 1;
+       if (ibuf_get_n8(msg, &nhlen) == -1)             /* nhlen */
+               goto fail;
 
        /* nexthop */
-       if (mrt_extract_addr(b, len, &re->nexthop, aid) == -1)
+       if (mrt_extract_addr(msg, &re->nexthop, aid) == -1)
                goto fail;
-       if (len < nhlen)
-               goto fail;
-       b += nhlen;
-       len -= nhlen;
 
        /* prefix */
-       ret = mrt_extract_prefix(b, len, aid, &r->prefix, &r->prefixlen,
-           verbose);
-       if (ret == -1)
+       if (mrt_extract_prefix(msg, aid, &r->prefix, &r->prefixlen,
+           verbose) == -1)
                goto fail;
-       b += ret;
-       len -= ret;
-
-       memcpy(&alen, b, sizeof(alen));
-       b += sizeof(alen);
-       len -= sizeof(alen);
-       alen = ntohs(alen);
 
-       /* attr */
-       if (len < alen)
+       if (ibuf_get_n16(msg, &alen) == -1 ||
+           ibuf_get_ibuf(msg, alen, &abuf) == -1)
                goto fail;
-       if (mrt_extract_attr(re, b, alen, r->prefix.aid, 0) == -1)
+       if (mrt_extract_attr(re, &abuf, r->prefix.aid, 0) == -1)
                goto fail;
-       b += alen;
-       len -= alen;
 
        return (0);
 fail:
@@ -769,73 +627,81 @@ fail:
 }
 
 int
-mrt_extract_attr(struct mrt_rib_entry *re, u_char *a, int alen, uint8_t aid,
+mrt_extract_attr(struct mrt_rib_entry *re, struct ibuf *buf, uint8_t aid,
     int as4)
 {
+       struct ibuf     abuf;
        struct mrt_attr *ap;
-       uint32_t        tmp;
-       uint16_t        attr_len;
-       uint8_t         type, flags, *attr;
+       size_t          alen, hlen;
+       uint8_t         type, flags;
 
        do {
-               if (alen < 3)
+               ibuf_from_ibuf(&abuf, buf);
+               if (ibuf_get_n8(&abuf, &flags) == -1 ||
+                   ibuf_get_n8(&abuf, &type) == -1)
                        return (-1);
-               attr = a;
-               flags = *a++;
-               alen -= 1;
-               type = *a++;
-               alen -= 1;
 
                if (flags & MRT_ATTR_EXTLEN) {
-                       if (alen < 2)
+                       uint16_t tmp16;
+                       if (ibuf_get_n16(&abuf, &tmp16) == -1)
                                return (-1);
-                       memcpy(&attr_len, a, sizeof(attr_len));
-                       attr_len = ntohs(attr_len);
-                       a += sizeof(attr_len);
-                       alen -= sizeof(attr_len);
+                       alen = tmp16;
+                       hlen = 4;
                } else {
-                       attr_len = *a++;
-                       alen -= 1;
+                       uint8_t tmp8;
+                       if (ibuf_get_n8(&abuf, &tmp8) == -1)
+                               return (-1);
+                       alen = tmp8;
+                       hlen = 3;
                }
+               if (ibuf_truncate(&abuf, alen) == -1)
+                       return (-1);
+               /* consume the attribute in buf before moving forward */
+               if (ibuf_skip(buf, hlen + alen) == -1)
+                       return (-1);
+
                switch (type) {
                case MRT_ATTR_ORIGIN:
-                       if (attr_len != 1)
+                       if (alen != 1)
+                               return (-1);
+                       if (ibuf_get_n8(&abuf, &re->origin) == -1)
                                return (-1);
-                       re->origin = *a;
                        break;
                case MRT_ATTR_ASPATH:
                        if (as4) {
-                               re->aspath_len = attr_len;
-                               if ((re->aspath = malloc(attr_len)) == NULL)
+                               re->aspath_len = alen;
+                               if ((re->aspath = malloc(alen)) == NULL)
                                        err(1, "malloc");
-                               memcpy(re->aspath, a, attr_len);
+                               if (ibuf_get(&abuf, re->aspath, alen) == -1)
+                                       return (-1);
                        } else {
-                               re->aspath = mrt_aspath_inflate(a, attr_len,
+                               re->aspath = mrt_aspath_inflate(&abuf,
                                    &re->aspath_len);
                                if (re->aspath == NULL)
                                        return (-1);
                        }
                        break;
                case MRT_ATTR_NEXTHOP:
-                       if (attr_len != 4)
+                       if (alen != 4)
                                return (-1);
                        if (aid != AID_INET)
                                break;
-                       memcpy(&tmp, a, sizeof(tmp));
+                       if (ibuf_get(&abuf, &re->nexthop.v4,
+                           sizeof(re->nexthop.v4)) == -1)
+                               return (-1);
                        re->nexthop.aid = AID_INET;
-                       re->nexthop.v4.s_addr = tmp;
                        break;
                case MRT_ATTR_MED:
-                       if (attr_len != 4)
+                       if (alen != 4)
+                               return (-1);
+                       if (ibuf_get_n32(&abuf, &re->med) == -1)
                                return (-1);
-                       memcpy(&tmp, a, sizeof(tmp));
-                       re->med = ntohl(tmp);
                        break;
                case MRT_ATTR_LOCALPREF:
-                       if (attr_len != 4)
+                       if (alen != 4)
+                               return (-1);
+                       if (ibuf_get_n32(&abuf, &re->local_pref) == -1)
                                return (-1);
-                       memcpy(&tmp, a, sizeof(tmp));
-                       re->local_pref = ntohl(tmp);
                        break;
                case MRT_ATTR_MP_REACH_NLRI:
                        /*
@@ -848,47 +714,49 @@ mrt_extract_attr(struct mrt_rib_entry *re, u_char *a, int alen, uint8_t aid,
                         * or the high byte of the AFI (old form)). If the
                         * first byte matches the expected nexthop length it
                         * is expected to be the RFC 6396 encoding.
+                        *
+                        * Checking for the hack skips over the nhlen.
                         */
-                       if (*a != attr_len - 1) {
-                               a += 3;
-                               alen -= 3;
-                               attr_len -= 3;
+                       {
+                               uint8_t hack;
+                               if (ibuf_get_n8(&abuf, &hack) == -1)
+                                       return (-1);
+                               if (hack != alen - 1) {
+                                       if (ibuf_skip(&abuf, 3) == -1)
+                                               return (-1);
+                               }
                        }
                        switch (aid) {
                        case AID_INET6:
-                               if (attr_len < sizeof(struct in6_addr) + 1)
+                               if (ibuf_get(&abuf, &re->nexthop.v6,
+                                   sizeof(re->nexthop.v6)) == -1)
                                        return (-1);
                                re->nexthop.aid = aid;
-                               memcpy(&re->nexthop.v6, a + 1,
-                                   sizeof(struct in6_addr));
                                break;
                        case AID_VPN_IPv4:
-                               if (attr_len < sizeof(uint64_t) +
-                                   sizeof(struct in_addr))
+                               if (ibuf_skip(&abuf, sizeof(uint64_t)) == -1 ||
+                                   ibuf_get(&abuf, &re->nexthop.v4,
+                                   sizeof(re->nexthop.v4)) == -1)
                                        return (-1);
                                re->nexthop.aid = aid;
-                               memcpy(&tmp, a + 1 + sizeof(uint64_t),
-                                   sizeof(tmp));
-                               re->nexthop.v4.s_addr = tmp;
                                break;
                        case AID_VPN_IPv6:
-                               if (attr_len < sizeof(uint64_t) +
-                                   sizeof(struct in6_addr))
+                               if (ibuf_skip(&abuf, sizeof(uint64_t)) == -1 ||
+                                   ibuf_get(&abuf, &re->nexthop.v6,
+                                   sizeof(re->nexthop.v6)) == -1)
                                        return (-1);
                                re->nexthop.aid = aid;
-                               memcpy(&re->nexthop.v6,
-                                   a + 1 + sizeof(uint64_t),
-                                   sizeof(struct in6_addr));
                                break;
                        }
                        break;
                case MRT_ATTR_AS4PATH:
                        if (!as4) {
                                free(re->aspath);
-                               re->aspath_len = attr_len;
-                               if ((re->aspath = malloc(attr_len)) == NULL)
+                               re->aspath_len = alen;
+                               if ((re->aspath = malloc(alen)) == NULL)
                                        err(1, "malloc");
-                               memcpy(re->aspath, a, attr_len);
+                               if (ibuf_get(&abuf, re->aspath, alen) == -1)
+                                       return (-1);
                                break;
                        }
                        /* FALLTHROUGH */
@@ -902,15 +770,15 @@ mrt_extract_attr(struct mrt_rib_entry *re, u_char *a, int alen, uint8_t aid,
                                err(1, "realloc");
                        re->attrs = ap;
                        ap = re->attrs + re->nattrs - 1;
-                       ap->attr_len = a + attr_len - attr;
+                       ibuf_rewind(&abuf);
+                       ap->attr_len = ibuf_size(&abuf);
                        if ((ap->attr = malloc(ap->attr_len)) == NULL)
                                err(1, "malloc");
-                       memcpy(ap->attr, attr, ap->attr_len);
+                       if (ibuf_get(&abuf, ap->attr, ap->attr_len) == -1)
+                               return (-1);
                        break;
                }
-               a += attr_len;
-               alen -= attr_len;
-       } while (alen > 0);
+       } while (ibuf_size(buf) > 0);
 
        return (0);
 }
@@ -939,106 +807,68 @@ mrt_free_rib(struct mrt_rib *r)
        free(r);
 }
 
-void
-mrt_free_bgp_state(struct mrt_bgp_state *s)
-{
-       free(s);
-}
-
-void
-mrt_free_bgp_msg(struct mrt_bgp_msg *m)
-{
-       free(m->msg);
-       free(m);
-}
-
 u_char *
-mrt_aspath_inflate(void *data, uint16_t len, uint16_t *newlen)
+mrt_aspath_inflate(struct ibuf *buf, uint16_t *newlen)
 {
-       uint8_t         *seg, *nseg, *ndata;
-       uint16_t         seg_size, olen, nlen;
-       uint8_t          seg_len;
-
-       /* first calculate the length of the aspath */
-       seg = data;
-       nlen = 0;
-       for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) {
-               seg_len = seg[1];
-               seg_size = 2 + sizeof(uint16_t) * seg_len;
-               nlen += 2 + sizeof(uint32_t) * seg_len;
-
-               if (seg_size > olen)
-                       return NULL;
-       }
+       struct ibuf *asbuf;
+       u_char *data;
+       size_t len;
 
-       *newlen = nlen;
-       if ((ndata = malloc(nlen)) == NULL)
-               err(1, "malloc");
+       *newlen = 0;
+       asbuf = aspath_inflate(buf);
+       if (asbuf == NULL)
+               return NULL;
 
-       /* then copy the aspath */
-       seg = data;
-       for (nseg = ndata; nseg < ndata + nlen; ) {
-               *nseg++ = *seg++;
-               *nseg++ = seg_len = *seg++;
-               for (; seg_len > 0; seg_len--) {
-                       *nseg++ = 0;
-                       *nseg++ = 0;
-                       *nseg++ = *seg++;
-                       *nseg++ = *seg++;
-               }
+       len = ibuf_size(asbuf);
+       if ((data = malloc(len)) == NULL)
+               err(1, "malloc");
+       if (ibuf_get(asbuf, data, len) == -1) {
+               ibuf_free(asbuf);
+               return (NULL);
        }
-
-       return (ndata);
+       ibuf_free(asbuf);
+       *newlen = len;
+       return (data);
 }
 
 int
-mrt_extract_addr(void *msg, u_int len, struct bgpd_addr *addr, uint8_t aid)
+mrt_extract_addr(struct ibuf *msg, struct bgpd_addr *addr, uint8_t aid)
 {
-       uint8_t *b = msg;
-
        memset(addr, 0, sizeof(*addr));
        switch (aid) {
        case AID_INET:
-               if (len < sizeof(struct in_addr))
+               if (ibuf_get(msg, &addr->v4, sizeof(addr->v4)) == -1)
                        return (-1);
-               addr->aid = aid;
-               memcpy(&addr->v4, b, sizeof(struct in_addr));
-               return sizeof(struct in_addr);
+               break;
        case AID_INET6:
-               if (len < sizeof(struct in6_addr))
+               if (ibuf_get(msg, &addr->v6, sizeof(addr->v6)) == -1)
                        return (-1);
-               addr->aid = aid;
-               memcpy(&addr->v6, b, sizeof(struct in6_addr));
-               return sizeof(struct in6_addr);
+               break;
        case AID_VPN_IPv4:
-               if (len < sizeof(uint64_t) + sizeof(struct in_addr))
-                       return (-1);
-               addr->aid = aid;
                /* XXX labelstack and rd missing */
-               memcpy(&addr->v4, b + sizeof(uint64_t),
-                   sizeof(struct in_addr));
-               return (sizeof(uint64_t) + sizeof(struct in_addr));
-       case AID_VPN_IPv6:
-               if (len < sizeof(uint64_t) + sizeof(struct in6_addr))
+               if (ibuf_skip(msg, sizeof(uint64_t)) == -1 ||
+                   ibuf_get(msg, &addr->v4, sizeof(addr->v4)) == -1)
                        return (-1);
-               addr->aid = aid;
+               break;
+       case AID_VPN_IPv6:
                /* XXX labelstack and rd missing */
-               memcpy(&addr->v6, b + sizeof(uint64_t),
-                   sizeof(struct in6_addr));
-               return (sizeof(uint64_t) + sizeof(struct in6_addr));
+               if (ibuf_skip(msg, sizeof(uint64_t)) == -1 ||
+                   ibuf_get(msg, &addr->v6, sizeof(addr->v6)) == -1)
+                       return (-1);
+               break;
        default:
                return (-1);
        }
+       addr->aid = aid;
+       return 0;
 }
 
 int
-mrt_extract_prefix(void *m, u_int len, uint8_t aid,
-    struct bgpd_addr *prefix, uint8_t *prefixlen, int verbose)
+mrt_extract_prefix(struct ibuf *msg, uint8_t aid, struct bgpd_addr *prefix,
+    uint8_t *prefixlen, int verbose)
 {
-       struct ibuf buf, *msg = &buf;
        int r;
 
-       ibuf_from_buffer(msg, m, len); /* XXX */
        switch (aid) {
        case AID_INET:
                r = nlri_get_prefix(msg, prefix, prefixlen);
@@ -1059,21 +889,16 @@ mrt_extract_prefix(void *m, u_int len, uint8_t aid,
        }
        if (r == -1 && verbose)
                printf("failed to parse prefix of AID %d\n", aid);
-       if (r != -1)
-               r = len - ibuf_size(msg); /* XXX */
        return r;
 }
 
-struct mrt_bgp_state *
-mrt_parse_state(struct mrt_hdr *hdr, void *msg, int verbose)
+int
+mrt_parse_state(struct mrt_bgp_state *s, struct mrt_hdr *hdr, struct ibuf *msg,
+    int verbose)
 {
        struct timespec          t;
-       struct mrt_bgp_state    *s;
-       uint8_t                 *b = msg;
-       u_int                    len = ntohl(hdr->length);
        uint32_t                 sas, das, usec;
-       uint16_t                 tmp16, afi;
-       int                      r;
+       uint16_t                 sas16, das16, afi;
        uint8_t                  aid;
 
        t.tv_sec = ntohl(hdr->timestamp);
@@ -1081,56 +906,27 @@ mrt_parse_state(struct mrt_hdr *hdr, void *msg, int verbose)
 
        /* handle the microsec field for _ET header */
        if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) {
-               memcpy(&usec, b, sizeof(usec));
-               b += sizeof(usec);
-               len -= sizeof(usec);
-               t.tv_nsec = ntohl(usec) * 1000;
+               if (ibuf_get_n32(msg, &usec) == -1)
+                       return (-1);
+               t.tv_nsec = usec * 1000;
        }
 
        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);
+               if (ibuf_get_n16(msg, &sas16) == -1 ||  /* source as */
+                   ibuf_get_n16(msg, &das16) == -1 ||  /* dest as */
+                   ibuf_skip(msg, 2) == -1 ||          /* if_index */
+                   ibuf_get_n16(msg, &afi) == -1)      /* afi */
+                       return (-1);
+               sas = sas16;
+               das = das16;
                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);
+               if (ibuf_get_n32(msg, &sas) == -1 ||    /* source as */
+                   ibuf_get_n32(msg, &das) == -1 ||    /* dest as */
+                   ibuf_skip(msg, 2) == -1 ||          /* if_index */
+                   ibuf_get_n16(msg, &afi) == -1)      /* afi */
+                       return (-1);
                break;
        default:
                errx(1, "mrt_parse_state: bad subtype");
@@ -1138,50 +934,34 @@ mrt_parse_state(struct mrt_hdr *hdr, void *msg, int verbose)
 
        /* src & dst addr */
        if ((aid = mrt_afi2aid(afi, -1, verbose)) == AID_UNSPEC)
-               return (NULL);
+               return (-1);
 
-       if ((s = calloc(1, sizeof(struct mrt_bgp_state))) == NULL)
-               err(1, "calloc");
+       memset(s, 0, sizeof(*s));
        s->time = t;
        s->src_as = sas;
        s->dst_as = das;
 
-       if ((r = mrt_extract_addr(b, len, &s->src, aid)) == -1)
-               goto fail;
-       b += r;
-       len -= r;
-       if ((r = mrt_extract_addr(b, len, &s->dst, aid)) == -1)
-               goto fail;
-       b += r;
-       len -= r;
+       if (mrt_extract_addr(msg, &s->src, aid) == -1)
+               return (-1);
+       if (mrt_extract_addr(msg, &s->dst, aid) == -1)
+               return (-1);
 
        /* 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);
+       if (ibuf_get_n16(msg, &s->old_state) == -1 ||
+           ibuf_get_n16(msg, &s->new_state) == -1)
+               return (-1);
 
-fail:
-       free(s);
-       return (NULL);
+       return (0);
 }
 
-struct mrt_bgp_msg *
-mrt_parse_msg(struct mrt_hdr *hdr, void *msg, int verbose)
+int
+mrt_parse_msg(struct mrt_bgp_msg *m, struct mrt_hdr *hdr, struct ibuf *msg,
+    int verbose)
 {
        struct timespec          t;
-       struct mrt_bgp_msg      *m;
-       uint8_t                 *b = msg;
-       u_int                    len = ntohl(hdr->length);
        uint32_t                 sas, das, usec;
-       uint16_t                 tmp16, afi;
-       int                      r, addpath = 0;
+       uint16_t                 sas16, das16, afi;
+       int                      addpath = 0;
        uint8_t                  aid;
 
        t.tv_sec = ntohl(hdr->timestamp);
@@ -1189,10 +969,9 @@ mrt_parse_msg(struct mrt_hdr *hdr, void *msg, int verbose)
 
        /* handle the microsec field for _ET header */
        if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) {
-               memcpy(&usec, b, sizeof(usec));
-               b += sizeof(usec);
-               len -= sizeof(usec);
-               t.tv_nsec = ntohl(usec) * 1000;
+               if (ibuf_get_n32(msg, &usec) == -1)
+                       return (-1);
+               t.tv_nsec = usec * 1000;
        }
 
        switch (ntohs(hdr->subtype)) {
@@ -1202,26 +981,13 @@ mrt_parse_msg(struct mrt_hdr *hdr, void *msg, int verbose)
                /* FALLTHROUGH */
        case BGP4MP_MESSAGE:
        case BGP4MP_MESSAGE_LOCAL:
-               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);
+               if (ibuf_get_n16(msg, &sas16) == -1 ||  /* source as */
+                   ibuf_get_n16(msg, &das16) == -1 ||  /* dest as */
+                   ibuf_skip(msg, 2) == -1 ||          /* if_index */
+                   ibuf_get_n16(msg, &afi) == -1)      /* afi */
+                       return (-1);
+               sas = sas16;
+               das = das16;
                break;
        case BGP4MP_MESSAGE_AS4_ADDPATH:
        case BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH:
@@ -1229,26 +995,11 @@ mrt_parse_msg(struct mrt_hdr *hdr, void *msg, int verbose)
                /* FALLTHROUGH */
        case BGP4MP_MESSAGE_AS4:
        case BGP4MP_MESSAGE_AS4_LOCAL:
-               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);
+               if (ibuf_get_n32(msg, &sas) == -1 ||    /* source as */
+                   ibuf_get_n32(msg, &das) == -1 ||    /* dest as */
+                   ibuf_skip(msg, 2) == -1 ||          /* if_index */
+                   ibuf_get_n16(msg, &afi) == -1)      /* afi */
+                       return (-1);
                break;
        default:
                errx(1, "mrt_parse_msg: bad subtype");
@@ -1256,36 +1007,19 @@ mrt_parse_msg(struct mrt_hdr *hdr, void *msg, int verbose)
 
        /* src & dst addr */
        if ((aid = mrt_afi2aid(afi, -1, verbose)) == AID_UNSPEC)
-               return (NULL);
+               return (-1);
 
-       if ((m = calloc(1, sizeof(struct mrt_bgp_msg))) == NULL)
-               err(1, "calloc");
+       memset(m, 0, sizeof(*m));
        m->time = t;
        m->src_as = sas;
        m->dst_as = das;
        m->add_path = addpath;
 
-       if ((r = mrt_extract_addr(b, len, &m->src, aid)) == -1)
-               goto fail;
-       b += r;
-       len -= r;
-       if ((r = mrt_extract_addr(b, len, &m->dst, aid)) == -1)
-               goto fail;
-       b += r;
-       len -= r;
+       if (mrt_extract_addr(msg, &m->src, aid) == -1 ||
+           mrt_extract_addr(msg, &m->dst, aid) == -1)
+               return (-1);
 
        /* 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);
+       ibuf_from_ibuf(&m->msg, msg);
+       return (0);
 }
index 116887c..d84d6c2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mrtparser.h,v 1.6 2024/01/23 15:56:48 claudio Exp $ */
+/*     $OpenBSD: mrtparser.h,v 1.7 2024/02/01 11:37:10 claudio Exp $ */
 /*
  * Copyright (c) 2011 Claudio Jeker <claudio@openbsd.org>
  *
@@ -76,9 +76,8 @@ struct mrt_bgp_msg {
        struct bgpd_addr dst;
        uint32_t         src_as;
        uint32_t         dst_as;
-       uint16_t         msg_len;
        uint8_t          add_path;
-       void            *msg;
+       struct ibuf      msg;
 };
 
 #define MRT_ATTR_ORIGIN                1