summaryrefslogtreecommitdiff
path: root/net/openbgpd/files/patch-bgpctl_mrtparser.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/openbgpd/files/patch-bgpctl_mrtparser.c')
-rw-r--r--net/openbgpd/files/patch-bgpctl_mrtparser.c977
1 files changed, 0 insertions, 977 deletions
diff --git a/net/openbgpd/files/patch-bgpctl_mrtparser.c b/net/openbgpd/files/patch-bgpctl_mrtparser.c
deleted file mode 100644
index 0d463c0064ef..000000000000
--- a/net/openbgpd/files/patch-bgpctl_mrtparser.c
+++ /dev/null
@@ -1,977 +0,0 @@
-Index: bgpctl/mrtparser.c
-===================================================================
-RCS file: bgpctl/mrtparser.c
-diff -N bgpctl/mrtparser.c
---- /dev/null 1 Jan 1970 00:00:00 -0000
-+++ bgpctl/mrtparser.c 13 Oct 2012 18:22:53 -0000 1.1.1.1
-@@ -0,0 +1,970 @@
-+/* $OpenBSD: mrtparser.c,v 1.2 2012/03/06 07:52:32 claudio Exp $ */
-+/*
-+ * Copyright (c) 2011 Claudio Jeker <claudio@openbsd.org>
-+ *
-+ * Permission to use, copy, modify, and distribute this software for any
-+ * purpose with or without fee is hereby granted, provided that the above
-+ * copyright notice and this permission notice appear in all copies.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+#include <sys/types.h>
-+#include <sys/socket.h>
-+#include <netinet/in.h>
-+#include <err.h>
-+#include <errno.h>
-+#include <limits.h>
-+#include <stdlib.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <unistd.h>
-+
-+#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 mrt_parse_dump(struct mrt_hdr *, void *, struct mrt_peer **,
-+ struct mrt_rib **);
-+int mrt_parse_dump_mp(struct mrt_hdr *, void *, struct mrt_peer **,
-+ struct mrt_rib **);
-+int mrt_extract_attr(struct mrt_rib_entry *, u_char *, int, sa_family_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 *, u_int16_t, u_int16_t *);
-+int mrt_extract_addr(void *, u_int, union mrt_addr *, sa_family_t);
-+
-+void *
-+mrt_read_msg(int fd, struct mrt_hdr *hdr)
-+{
-+ void *buf;
-+
-+ bzero(hdr, 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);
-+
-+ if (mrt_read_buf(fd, buf, ntohl(hdr->length)) != ntohl(hdr->length)) {
-+ free(buf);
-+ return (NULL);
-+ }
-+ return (buf);
-+}
-+
-+size_t
-+mrt_read_buf(int fd, void *buf, size_t len)
-+{
-+ char *b = buf;
-+ ssize_t n;
-+
-+ while (len > 0) {
-+ if ((n = read(fd, b, len)) == -1) {
-+ if (errno == EINTR)
-+ continue;
-+ err(1, "read");
-+ }
-+ if (n == 0)
-+ break;
-+ b += n;
-+ len -= n;
-+ }
-+
-+ return (b - (char *)buf);
-+}
-+
-+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;
-+
-+ while ((msg = mrt_read_msg(fd, &h))) {
-+ switch (ntohs(h.type)) {
-+ case MSG_NULL:
-+ case MSG_START:
-+ case MSG_DIE:
-+ case MSG_I_AM_DEAD:
-+ case MSG_PEER_DOWN:
-+ case MSG_PROTOCOL_BGP:
-+ case MSG_PROTOCOL_IDRP:
-+ case MSG_PROTOCOL_BGP4PLUS:
-+ case MSG_PROTOCOL_BGP4PLUS1:
-+ if (verbose)
-+ printf("deprecated MRT type %d\n",
-+ ntohs(h.type));
-+ break;
-+ case MSG_PROTOCOL_RIP:
-+ case MSG_PROTOCOL_RIPNG:
-+ case MSG_PROTOCOL_OSPF:
-+ case MSG_PROTOCOL_ISIS_ET:
-+ case MSG_PROTOCOL_ISIS:
-+ case MSG_PROTOCOL_OSPFV3_ET:
-+ case MSG_PROTOCOL_OSPFV3:
-+ if (verbose)
-+ printf("unsuported MRT type %d\n",
-+ ntohs(h.type));
-+ break;
-+ case MSG_TABLE_DUMP:
-+ switch (ntohs(h.subtype)) {
-+ case MRT_DUMP_AFI_IP:
-+ case MRT_DUMP_AFI_IPv6:
-+ if (p->dump == NULL)
-+ break;
-+ if (mrt_parse_dump(&h, msg, &pctx, &r) == 0) {
-+ p->dump(r, pctx, p->arg);
-+ mrt_free_rib(r);
-+ }
-+ break;
-+ default:
-+ if (verbose)
-+ printf("unknown AFI %d in table dump\n",
-+ ntohs(h.subtype));
-+ break;
-+ }
-+ break;
-+ case MSG_TABLE_DUMP_V2:
-+ switch (ntohs(h.subtype)) {
-+ case MRT_DUMP_V2_PEER_INDEX_TABLE:
-+ if (p->dump == NULL)
-+ break;
-+ if (pctx)
-+ mrt_free_peers(pctx);
-+ pctx = mrt_parse_v2_peer(&h, msg);
-+ break;
-+ case MRT_DUMP_V2_RIB_IPV4_UNICAST:
-+ case MRT_DUMP_V2_RIB_IPV4_MULTICAST:
-+ case MRT_DUMP_V2_RIB_IPV6_UNICAST:
-+ case MRT_DUMP_V2_RIB_IPV6_MULTICAST:
-+ case MRT_DUMP_V2_RIB_GENERIC:
-+ if (p->dump == NULL)
-+ break;
-+ r = mrt_parse_v2_rib(&h, msg);
-+ if (r) {
-+ p->dump(r, pctx, p->arg);
-+ mrt_free_rib(r);
-+ }
-+ break;
-+ default:
-+ if (verbose)
-+ printf("unhandled BGP4MP subtype %d\n",
-+ ntohs(h.subtype));
-+ break;
-+ }
-+ break;
-+ case MSG_PROTOCOL_BGP4MP_ET:
-+ /* currently just ignore the microsec field */
-+ msg = (char *)msg + sizeof(u_int32_t);
-+ h.length -= sizeof(u_int32_t);
-+ /* FALLTHROUGH */
-+ case MSG_PROTOCOL_BGP4MP:
-+ 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");
-+ 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");
-+ 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);
-+ mrt_free_rib(r);
-+ }
-+ break;
-+ default:
-+ if (verbose)
-+ printf("unhandled BGP4MP subtype %d\n",
-+ ntohs(h.subtype));
-+ break;
-+ }
-+ break;
-+ default:
-+ if (verbose)
-+ printf("unknown MRT type %d\n", ntohs(h.type));
-+ break;
-+ }
-+ free(msg);
-+ }
-+ if (pctx)
-+ mrt_free_peers(pctx);
-+}
-+
-+struct mrt_peer *
-+mrt_parse_v2_peer(struct mrt_hdr *hdr, void *msg)
-+{
-+ struct mrt_peer_entry *peers;
-+ struct mrt_peer *p;
-+ u_int8_t *b = msg;
-+ u_int32_t bid, as4;
-+ u_int16_t cnt, i, as2;
-+ u_int len = ntohl(hdr->length);
-+
-+ if (len < 8) /* min msg size */
-+ return NULL;
-+
-+ p = calloc(1, sizeof(struct mrt_peer));
-+ if (p == NULL)
-+ 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);
-+
-+ /* 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);
-+ p->view[cnt] = 0;
-+ } else
-+ if ((p->view = strdup("")) == NULL)
-+ err(1, "strdup");
-+ b += cnt;
-+ len -= cnt;
-+
-+ /* peer_count */
-+ if (len < sizeof(cnt))
-+ 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)
-+ err(1, "calloc");
-+ for (i = 0; i < cnt; i++) {
-+ u_int8_t type;
-+
-+ if (len < sizeof(u_int8_t) + sizeof(u_int32_t))
-+ 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,
-+ AF_INET6) == -1)
-+ goto fail;
-+ b += sizeof(struct in6_addr);
-+ len -= sizeof(struct in6_addr);
-+ } else {
-+ if (mrt_extract_addr(b, len, &peers[i].addr,
-+ AF_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);
-+ } else {
-+ memcpy(&as2, b, sizeof(as2));
-+ b += sizeof(as2);
-+ len -= sizeof(as2);
-+ as4 = ntohs(as2);
-+ }
-+ peers[i].asnum = as4;
-+ }
-+ p->peers = peers;
-+ p->npeers = cnt;
-+ return (p);
-+fail:
-+ mrt_free_peers(p);
-+ return (NULL);
-+}
-+
-+struct mrt_rib *
-+mrt_parse_v2_rib(struct mrt_hdr *hdr, void *msg)
-+{
-+ struct mrt_rib_entry *entries;
-+ struct mrt_rib *r;
-+ u_int8_t *b = msg;
-+ u_int len = ntohl(hdr->length);
-+ u_int32_t snum;
-+ u_int16_t cnt, i;
-+ u_int8_t plen;
-+
-+ 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);
-+
-+ switch (ntohs(hdr->subtype)) {
-+ case MRT_DUMP_V2_RIB_IPV4_UNICAST:
-+ case MRT_DUMP_V2_RIB_IPV4_MULTICAST:
-+ plen = *b++;
-+ len -= 1;
-+ if (len < MRT_PREFIX_LEN(plen))
-+ goto fail;
-+ r->prefix.sin.sin_family = AF_INET;
-+ r->prefix.sin.sin_len = sizeof(struct sockaddr_in);
-+ memcpy(&r->prefix.sin.sin_addr, b, MRT_PREFIX_LEN(plen));
-+ b += MRT_PREFIX_LEN(plen);
-+ len -= MRT_PREFIX_LEN(plen);
-+ r->prefixlen = plen;
-+ break;
-+ case MRT_DUMP_V2_RIB_IPV6_UNICAST:
-+ case MRT_DUMP_V2_RIB_IPV6_MULTICAST:
-+ plen = *b++;
-+ len -= 1;
-+ if (len < MRT_PREFIX_LEN(plen))
-+ goto fail;
-+ r->prefix.sin6.sin6_family = AF_INET6;
-+ r->prefix.sin6.sin6_len = sizeof(struct sockaddr_in6);
-+ memcpy(&r->prefix.sin6.sin6_addr, b, MRT_PREFIX_LEN(plen));
-+ b += MRT_PREFIX_LEN(plen);
-+ len -= MRT_PREFIX_LEN(plen);
-+ r->prefixlen = plen;
-+ break;
-+ case MRT_DUMP_V2_RIB_GENERIC:
-+ /* XXX unhandled */
-+ errx(1, "MRT_DUMP_V2_RIB_GENERIC subtype not yet implemented");
-+ goto fail;
-+ }
-+
-+ /* entries count */
-+ if (len < sizeof(cnt))
-+ 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)
-+ err(1, "calloc");
-+ for (i = 0; i < cnt; i++) {
-+ u_int32_t otm;
-+ u_int16_t pix, alen;
-+ if (len < 2 * sizeof(u_int16_t) + sizeof(u_int32_t))
-+ goto fail;
-+ /* peer index */
-+ memcpy(&pix, b, sizeof(pix));
-+ b += sizeof(pix);
-+ len -= sizeof(pix);
-+ entries[i].peer_idx = ntohs(pix);
-+
-+ /* originated */
-+ memcpy(&otm, b, sizeof(otm));
-+ b += sizeof(otm);
-+ len -= sizeof(otm);
-+ entries[i].originated = ntohl(otm);
-+
-+ /* attr_len */
-+ memcpy(&alen, b, sizeof(alen));
-+ b += sizeof(alen);
-+ len -= sizeof(alen);
-+ alen = ntohs(alen);
-+
-+ /* attr */
-+ if (len < alen)
-+ goto fail;
-+ if (mrt_extract_attr(&entries[i], b, alen,
-+ r->prefix.sa.sa_family, 1) == -1)
-+ goto fail;
-+ b += alen;
-+ len -= alen;
-+ }
-+ r->entries = entries;
-+ return (r);
-+fail:
-+ mrt_free_rib(r);
-+ return (NULL);
-+}
-+
-+int
-+mrt_parse_dump(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp,
-+ struct mrt_rib **rp)
-+{
-+ struct mrt_peer *p;
-+ struct mrt_rib *r;
-+ struct mrt_rib_entry *re;
-+ u_int8_t *b = msg;
-+ u_int len = ntohl(hdr->length);
-+ u_int16_t asnum, alen;
-+
-+ if (*pp == NULL) {
-+ *pp = calloc(1, sizeof(struct mrt_peer));
-+ if (*pp == NULL)
-+ err(1, "calloc");
-+ (*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry));
-+ if ((*pp)->peers == NULL)
-+ err(1, "calloc");
-+ (*pp)->npeers = 1;
-+ }
-+ p = *pp;
-+
-+ *rp = r = calloc(1, sizeof(struct mrt_rib));
-+ if (r == NULL)
-+ err(1, "calloc");
-+ re = calloc(1, sizeof(struct mrt_rib_entry));
-+ if (re == NULL)
-+ err(1, "calloc");
-+ r->nentries = 1;
-+ r->entries = re;
-+
-+ if (len < 2 * sizeof(u_int16_t))
-+ goto fail;
-+ /* view */
-+ b += sizeof(u_int16_t);
-+ len -= sizeof(u_int16_t);
-+ /* seqnum */
-+ memcpy(&r->seqnum, b, sizeof(u_int16_t));
-+ b += sizeof(u_int16_t);
-+ len -= sizeof(u_int16_t);
-+ r->seqnum = ntohs(r->seqnum);
-+
-+ switch (ntohs(hdr->subtype)) {
-+ case MRT_DUMP_AFI_IP:
-+ if (mrt_extract_addr(b, len, &r->prefix, AF_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, AF_INET6) == -1)
-+ goto fail;
-+ b += sizeof(struct in6_addr);
-+ len -= sizeof(struct in6_addr);
-+ break;
-+ }
-+ if (len < 2 * sizeof(u_int32_t) + 2 * sizeof(u_int16_t) + 2)
-+ goto fail;
-+ r->prefixlen = *b++;
-+ len -= 1;
-+ /* status */
-+ b += 1;
-+ len -= 1;
-+ /* originated */
-+ memcpy(&re->originated, b, sizeof(u_int32_t));
-+ b += sizeof(u_int32_t);
-+ len -= sizeof(u_int32_t);
-+ re->originated = ntohl(re->originated);
-+ /* peer ip */
-+ switch (ntohs(hdr->subtype)) {
-+ case MRT_DUMP_AFI_IP:
-+ if (mrt_extract_addr(b, len, &p->peers->addr, AF_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, AF_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);
-+
-+ memcpy(&alen, b, sizeof(alen));
-+ b += sizeof(alen);
-+ len -= sizeof(alen);
-+ alen = ntohs(alen);
-+
-+ /* attr */
-+ if (len < alen)
-+ goto fail;
-+ if (mrt_extract_attr(re, b, alen, r->prefix.sa.sa_family, 0) == -1)
-+ goto fail;
-+ b += alen;
-+ len -= alen;
-+
-+ return (0);
-+fail:
-+ mrt_free_rib(r);
-+ return (-1);
-+}
-+
-+int
-+mrt_parse_dump_mp(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp,
-+ struct mrt_rib **rp)
-+{
-+ struct mrt_peer *p;
-+ struct mrt_rib *r;
-+ struct mrt_rib_entry *re;
-+ u_int8_t *b = msg;
-+ u_int len = ntohl(hdr->length);
-+ u_int16_t asnum, alen, afi;
-+ u_int8_t safi, nhlen;
-+ sa_family_t af;
-+
-+ if (*pp == NULL) {
-+ *pp = calloc(1, sizeof(struct mrt_peer));
-+ if (*pp == NULL)
-+ err(1, "calloc");
-+ (*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry));
-+ if ((*pp)->peers == NULL)
-+ err(1, "calloc");
-+ (*pp)->npeers = 1;
-+ }
-+ p = *pp;
-+
-+ *rp = r = calloc(1, sizeof(struct mrt_rib));
-+ if (r == NULL)
-+ err(1, "calloc");
-+ re = calloc(1, sizeof(struct mrt_rib_entry));
-+ if (re == NULL)
-+ err(1, "calloc");
-+ r->nentries = 1;
-+ r->entries = re;
-+
-+ if (len < 4 * sizeof(u_int16_t))
-+ goto fail;
-+ /* source AS */
-+ b += sizeof(u_int16_t);
-+ len -= sizeof(u_int16_t);
-+ /* dest AS */
-+ memcpy(&asnum, b, sizeof(asnum));
-+ b += sizeof(asnum);
-+ len -= sizeof(asnum);
-+ p->peers->asnum = ntohs(asnum);
-+ /* iface index */
-+ b += sizeof(u_int16_t);
-+ len -= sizeof(u_int16_t);
-+ /* afi */
-+ memcpy(&afi, b, sizeof(afi));
-+ b += sizeof(afi);
-+ len -= sizeof(afi);
-+ afi = ntohs(afi);
-+
-+ /* 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);
-+ /* dest IP */
-+ if (mrt_extract_addr(b, len, &p->peers->addr, AF_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);
-+ /* dest IP */
-+ if (mrt_extract_addr(b, len, &p->peers->addr, AF_INET6) == -1)
-+ goto fail;
-+ b += sizeof(struct in6_addr);
-+ len -= sizeof(struct in6_addr);
-+ break;
-+ }
-+
-+ if (len < 2 * sizeof(u_int16_t) + 2 * sizeof(u_int32_t))
-+ goto fail;
-+ /* view + status */
-+ b += 2 * sizeof(u_int16_t);
-+ len -= 2 * sizeof(u_int16_t);
-+ /* originated */
-+ memcpy(&re->originated, b, sizeof(u_int32_t));
-+ b += sizeof(u_int32_t);
-+ len -= sizeof(u_int32_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;
-+
-+ switch (afi) {
-+ case MRT_DUMP_AFI_IP:
-+ if (safi == 1 || safi == 2) {
-+ af = AF_INET;
-+ break;
-+ } else if (safi == 128) {
-+ af = AF_VPNv4;
-+ break;
-+ }
-+ goto fail;
-+ case MRT_DUMP_AFI_IPv6:
-+ if (safi != 1 && safi != 2)
-+ goto fail;
-+ af = AF_INET6;
-+ break;
-+ default:
-+ goto fail;
-+ }
-+
-+ /* nhlen */
-+ nhlen = *b++;
-+ len -= 1;
-+
-+ /* nexthop */
-+ if (mrt_extract_addr(b, len, &re->nexthop, af) == -1)
-+ goto fail;
-+ if (len < nhlen)
-+ goto fail;
-+ b += nhlen;
-+ len -= nhlen;
-+
-+ if (len < 1)
-+ goto fail;
-+ r->prefixlen = *b++;
-+ len -= 1;
-+
-+ /* prefix */
-+ switch (af) {
-+ case AF_INET:
-+ if (len < MRT_PREFIX_LEN(r->prefixlen))
-+ goto fail;
-+ r->prefix.sin.sin_family = AF_INET;
-+ r->prefix.sin.sin_len = sizeof(struct sockaddr_in);
-+ memcpy(&r->prefix.sin.sin_addr, b,
-+ MRT_PREFIX_LEN(r->prefixlen));
-+ b += MRT_PREFIX_LEN(r->prefixlen);
-+ len -= MRT_PREFIX_LEN(r->prefixlen);
-+ break;
-+ case AF_INET6:
-+ if (len < MRT_PREFIX_LEN(r->prefixlen))
-+ goto fail;
-+ r->prefix.sin6.sin6_family = AF_INET6;
-+ r->prefix.sin6.sin6_len = sizeof(struct sockaddr_in6);
-+ memcpy(&r->prefix.sin6.sin6_addr, b,
-+ MRT_PREFIX_LEN(r->prefixlen));
-+ b += MRT_PREFIX_LEN(r->prefixlen);
-+ len -= MRT_PREFIX_LEN(r->prefixlen);
-+ break;
-+ case AF_VPNv4:
-+ if (len < MRT_PREFIX_LEN(r->prefixlen))
-+ goto fail;
-+ errx(1, "AF_VPNv4 handling not yet implemented");
-+ goto fail;
-+ }
-+
-+ memcpy(&alen, b, sizeof(alen));
-+ b += sizeof(alen);
-+ len -= sizeof(alen);
-+ alen = ntohs(alen);
-+
-+ /* attr */
-+ if (len < alen)
-+ goto fail;
-+ if (mrt_extract_attr(re, b, alen, r->prefix.sa.sa_family, 0) == -1)
-+ goto fail;
-+ b += alen;
-+ len -= alen;
-+
-+ return (0);
-+fail:
-+ mrt_free_rib(r);
-+ return (-1);
-+}
-+
-+int
-+mrt_extract_attr(struct mrt_rib_entry *re, u_char *a, int alen, sa_family_t af,
-+ int as4)
-+{
-+ struct mrt_attr *ap;
-+ u_int32_t tmp;
-+ u_int16_t attr_len;
-+ u_int8_t type, flags, *attr;
-+
-+ do {
-+ if (alen < 3)
-+ return (-1);
-+ attr = a;
-+ flags = *a++;
-+ alen -= 1;
-+ type = *a++;
-+ alen -= 1;
-+
-+ if (flags & MRT_ATTR_EXTLEN) {
-+ if (alen < 2)
-+ return (-1);
-+ memcpy(&attr_len, a, sizeof(attr_len));
-+ attr_len = ntohs(attr_len);
-+ a += sizeof(attr_len);
-+ alen -= sizeof(attr_len);
-+ } else {
-+ attr_len = *a++;
-+ alen -= 1;
-+ }
-+ switch (type) {
-+ case MRT_ATTR_ORIGIN:
-+ if (attr_len != 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)
-+ err(1, "malloc");
-+ memcpy(re->aspath, a, attr_len);
-+ } else {
-+ re->aspath = mrt_aspath_inflate(a, attr_len,
-+ &re->aspath_len);
-+ if (re->aspath == NULL)
-+ return (-1);
-+ }
-+ break;
-+ case MRT_ATTR_NEXTHOP:
-+ if (attr_len != 4)
-+ return (-1);
-+ if (af != AF_INET)
-+ break;
-+ memcpy(&tmp, a, sizeof(tmp));
-+ re->nexthop.sin.sin_len = sizeof(struct sockaddr_in);
-+ re->nexthop.sin.sin_family = AF_INET;
-+ re->nexthop.sin.sin_addr.s_addr = tmp;
-+ break;
-+ case MRT_ATTR_MED:
-+ if (attr_len != 4)
-+ return (-1);
-+ memcpy(&tmp, a, sizeof(tmp));
-+ re->med = ntohl(tmp);
-+ break;
-+ case MRT_ATTR_LOCALPREF:
-+ if (attr_len != 4)
-+ return (-1);
-+ memcpy(&tmp, a, sizeof(tmp));
-+ re->local_pref = ntohl(tmp);
-+ break;
-+ case MRT_ATTR_MP_REACH_NLRI:
-+ /*
-+ * XXX horrible hack:
-+ * Once again IETF and the real world differ in the
-+ * implementation. In short the abbreviated MP_NLRI
-+ * hack in the standard is not used in real life.
-+ * Detect the two cases by looking at the first byte
-+ * of the payload (either the nexthop addr length (RFC)
-+ * 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.
-+ */
-+ if (*a != attr_len - 1) {
-+ a += 3;
-+ alen -= 3;
-+ attr_len -= 3;
-+ }
-+ switch (af) {
-+ case AF_INET6:
-+ if (attr_len < sizeof(struct in6_addr) + 1)
-+ return (-1);
-+ re->nexthop.sin6.sin6_len =
-+ sizeof(struct sockaddr_in6);
-+ re->nexthop.sin6.sin6_family = AF_INET6;
-+ memcpy(&re->nexthop.sin6.sin6_addr, a + 1,
-+ sizeof(struct in6_addr));
-+ break;
-+ case AF_VPNv4:
-+ if (attr_len < sizeof(u_int64_t) +
-+ sizeof(struct in_addr))
-+ return (-1);
-+ re->nexthop.svpn4.sv_len =
-+ sizeof(struct sockaddr_vpn4);
-+ re->nexthop.svpn4.sv_family = AF_VPNv4;
-+ memcpy(&tmp, a + 1 + sizeof(u_int64_t),
-+ sizeof(tmp));
-+ re->nexthop.svpn4.sv_addr.s_addr = tmp;
-+ break;
-+ }
-+ break;
-+ case MRT_ATTR_AS4PATH:
-+ if (!as4) {
-+ if (re->aspath)
-+ free(re->aspath);
-+ re->aspath_len = attr_len;
-+ if ((re->aspath = malloc(attr_len)) == NULL)
-+ err(1, "malloc");
-+ memcpy(re->aspath, a, attr_len);
-+ break;
-+ }
-+ /* FALLTHROUGH */
-+ default:
-+ re->nattrs++;
-+ if (re->nattrs >= UCHAR_MAX)
-+ err(1, "too many attributes");
-+ ap = realloc(re->attrs,
-+ re->nattrs * sizeof(struct mrt_attr));
-+ if (ap == NULL)
-+ err(1, "realloc");
-+ re->attrs = ap;
-+ ap = re->attrs + re->nattrs - 1;
-+ ap->attr_len = a + attr_len - attr;
-+ if ((ap->attr = malloc(ap->attr_len)) == NULL)
-+ err(1, "malloc");
-+ memcpy(ap->attr, attr, ap->attr_len);
-+ break;
-+ }
-+ a += attr_len;
-+ alen -= attr_len;
-+ } while (alen > 0);
-+
-+ return (0);
-+}
-+
-+void
-+mrt_free_peers(struct mrt_peer *p)
-+{
-+ free(p->peers);
-+ free(p->view);
-+ free(p);
-+}
-+
-+void
-+mrt_free_rib(struct mrt_rib *r)
-+{
-+ u_int16_t i, j;
-+
-+ for (i = 0; i < r->nentries && r->entries; i++) {
-+ for (j = 0; j < r->entries[i].nattrs; j++)
-+ free(r->entries[i].attrs[j].attr);
-+ free(r->entries[i].attrs);
-+ free(r->entries[i].aspath);
-+ }
-+
-+ free(r->entries);
-+ 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, u_int16_t len, u_int16_t *newlen)
-+{
-+ u_int8_t *seg, *nseg, *ndata;
-+ u_int16_t seg_size, olen, nlen;
-+ u_int8_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(u_int16_t) * seg_len;
-+ nlen += 2 + sizeof(u_int32_t) * seg_len;
-+
-+ if (seg_size > olen)
-+ return NULL;
-+ }
-+
-+ *newlen = nlen;
-+ if ((ndata = malloc(nlen)) == NULL)
-+ err(1, "malloc");
-+
-+ /* 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++;
-+ }
-+ }
-+
-+ return (ndata);
-+}
-+
-+int
-+mrt_extract_addr(void *msg, u_int len, union mrt_addr *addr, sa_family_t af)
-+{
-+ u_int8_t *b = msg;
-+
-+ switch (af) {
-+ case AF_INET:
-+ if (len < sizeof(struct in_addr))
-+ return (-1);
-+ addr->sin.sin_family = AF_INET;
-+ addr->sin.sin_len = sizeof(struct sockaddr_in);
-+ memcpy(&addr->sin.sin_addr, b, sizeof(struct in_addr));
-+ return sizeof(struct in_addr);
-+ case AF_INET6:
-+ if (len < sizeof(struct in6_addr))
-+ return (-1);
-+ addr->sin6.sin6_family = AF_INET6;
-+ addr->sin6.sin6_len = sizeof(struct sockaddr_in6);
-+ memcpy(&addr->sin6.sin6_addr, b, sizeof(struct in6_addr));
-+ return sizeof(struct in6_addr);
-+ case AF_VPNv4:
-+ if (len < sizeof(u_int64_t) + sizeof(struct in_addr))
-+ return (-1);
-+ addr->svpn4.sv_len = sizeof(struct sockaddr_vpn4);
-+ addr->svpn4.sv_family = AF_VPNv4;
-+ memcpy(&addr->svpn4.sv_addr, b + sizeof(u_int64_t),
-+ sizeof(struct in_addr));
-+ return (sizeof(u_int64_t) + sizeof(struct in_addr));
-+ default:
-+ return (-1);
-+ }
-+}