diff options
Diffstat (limited to 'net/openbgpd/files/patch-bgpctl_mrtparser.c')
-rw-r--r-- | net/openbgpd/files/patch-bgpctl_mrtparser.c | 977 |
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); -+ } -+} |