summaryrefslogtreecommitdiff
path: root/net/openbgpd/files/patch-bgpctl_mrtparser.c
diff options
context:
space:
mode:
authorHiroki Sato <hrs@FreeBSD.org>2012-10-13 19:40:42 +0000
committerHiroki Sato <hrs@FreeBSD.org>2012-10-13 19:40:42 +0000
commit256f3a3dba73b803a29ae012ff6e136fd72e7294 (patch)
treee533d59b6703e89ff55f633cba2f2285d9b30e49 /net/openbgpd/files/patch-bgpctl_mrtparser.c
parentUpdate to Wine 1.5.15. This includes the following changes: (diff)
Update to 5.2.20121014.
Feature safe: yes
Diffstat (limited to 'net/openbgpd/files/patch-bgpctl_mrtparser.c')
-rw-r--r--net/openbgpd/files/patch-bgpctl_mrtparser.c977
1 files changed, 977 insertions, 0 deletions
diff --git a/net/openbgpd/files/patch-bgpctl_mrtparser.c b/net/openbgpd/files/patch-bgpctl_mrtparser.c
new file mode 100644
index 000000000000..0d463c0064ef
--- /dev/null
+++ b/net/openbgpd/files/patch-bgpctl_mrtparser.c
@@ -0,0 +1,977 @@
+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);
++ }
++}