diff options
author | Hiroki Sato <hrs@FreeBSD.org> | 2012-10-13 19:40:42 +0000 |
---|---|---|
committer | Hiroki Sato <hrs@FreeBSD.org> | 2012-10-13 19:40:42 +0000 |
commit | 256f3a3dba73b803a29ae012ff6e136fd72e7294 (patch) | |
tree | e533d59b6703e89ff55f633cba2f2285d9b30e49 /net/openbgpd/files/patch-bgpctl_mrtparser.c | |
parent | Update 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.c | 977 |
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); ++ } ++} |