xref: /openbsd-src/usr.sbin/bgpctl/mrtparser.c (revision 6b941460852776d7795c139bd9a6ee4d236b9d40)
1*6b941460Sclaudio /*	$OpenBSD: mrtparser.c,v 1.22 2024/02/01 11:37:10 claudio Exp $ */
2a20554fdSclaudio /*
3a20554fdSclaudio  * Copyright (c) 2011 Claudio Jeker <claudio@openbsd.org>
4a20554fdSclaudio  *
5a20554fdSclaudio  * Permission to use, copy, modify, and distribute this software for any
6a20554fdSclaudio  * purpose with or without fee is hereby granted, provided that the above
7a20554fdSclaudio  * copyright notice and this permission notice appear in all copies.
8a20554fdSclaudio  *
9a20554fdSclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10a20554fdSclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11a20554fdSclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12a20554fdSclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13a20554fdSclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14a20554fdSclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15a20554fdSclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16a20554fdSclaudio  */
17a20554fdSclaudio #include <sys/types.h>
18a20554fdSclaudio #include <sys/socket.h>
19a20554fdSclaudio #include <netinet/in.h>
20a20554fdSclaudio #include <err.h>
21a20554fdSclaudio #include <errno.h>
22a20554fdSclaudio #include <limits.h>
23a20554fdSclaudio #include <stdlib.h>
24a20554fdSclaudio #include <stdio.h>
25a20554fdSclaudio #include <string.h>
2685411ad9Sclaudio #include <time.h>
27a20554fdSclaudio #include <unistd.h>
28a20554fdSclaudio 
29a20554fdSclaudio #include "mrt.h"
30a20554fdSclaudio #include "mrtparser.h"
31a20554fdSclaudio 
32*6b941460Sclaudio struct mrt_peer	*mrt_parse_v2_peer(struct mrt_hdr *, struct ibuf *);
33*6b941460Sclaudio struct mrt_rib	*mrt_parse_v2_rib(struct mrt_hdr *, struct ibuf *, int);
34*6b941460Sclaudio int	mrt_parse_dump(struct mrt_hdr *, struct ibuf *, struct mrt_peer **,
35a20554fdSclaudio 	    struct mrt_rib **);
36*6b941460Sclaudio int	mrt_parse_dump_mp(struct mrt_hdr *, struct ibuf *, struct mrt_peer **,
37dcaecb8bSclaudio 	    struct mrt_rib **, int);
38*6b941460Sclaudio int	mrt_extract_attr(struct mrt_rib_entry *, struct ibuf *, uint8_t, int);
39a20554fdSclaudio 
40a20554fdSclaudio void	mrt_free_peers(struct mrt_peer *);
41a20554fdSclaudio void	mrt_free_rib(struct mrt_rib *);
42a20554fdSclaudio 
43*6b941460Sclaudio u_char *mrt_aspath_inflate(struct ibuf *, uint16_t *);
44*6b941460Sclaudio int	mrt_extract_addr(struct ibuf *, struct bgpd_addr *, uint8_t);
45*6b941460Sclaudio int	mrt_extract_prefix(struct ibuf *, uint8_t, struct bgpd_addr *,
4659154960Sclaudio 	    uint8_t *, int);
47a20554fdSclaudio 
48*6b941460Sclaudio int	mrt_parse_state(struct mrt_bgp_state *, struct mrt_hdr *,
49*6b941460Sclaudio 	    struct ibuf *, int);
50*6b941460Sclaudio int	mrt_parse_msg(struct mrt_bgp_msg *, struct mrt_hdr *,
51*6b941460Sclaudio 	    struct ibuf *, int);
52e86c4bdeSclaudio 
53*6b941460Sclaudio static size_t
mrt_read_buf(int fd,void * buf,size_t len)54a20554fdSclaudio mrt_read_buf(int fd, void *buf, size_t len)
55a20554fdSclaudio {
56a20554fdSclaudio 	char *b = buf;
57a20554fdSclaudio 	ssize_t n;
58a20554fdSclaudio 
59a20554fdSclaudio 	while (len > 0) {
60a20554fdSclaudio 		if ((n = read(fd, b, len)) == -1) {
61a20554fdSclaudio 			if (errno == EINTR)
62a20554fdSclaudio 				continue;
63a20554fdSclaudio 			err(1, "read");
64a20554fdSclaudio 		}
65a20554fdSclaudio 		if (n == 0)
66a20554fdSclaudio 			break;
67a20554fdSclaudio 		b += n;
68a20554fdSclaudio 		len -= n;
69a20554fdSclaudio 	}
70a20554fdSclaudio 
71a20554fdSclaudio 	return (b - (char *)buf);
72a20554fdSclaudio }
73a20554fdSclaudio 
74*6b941460Sclaudio static struct ibuf *
mrt_read_msg(int fd,struct mrt_hdr * hdr)75*6b941460Sclaudio mrt_read_msg(int fd, struct mrt_hdr *hdr)
76*6b941460Sclaudio {
77*6b941460Sclaudio 	struct ibuf *buf;
78*6b941460Sclaudio 	size_t len;
79*6b941460Sclaudio 
80*6b941460Sclaudio 	memset(hdr, 0, sizeof(*hdr));
81*6b941460Sclaudio 	if (mrt_read_buf(fd, hdr, sizeof(*hdr)) != sizeof(*hdr))
82*6b941460Sclaudio 		return (NULL);
83*6b941460Sclaudio 
84*6b941460Sclaudio 	len = ntohl(hdr->length);
85*6b941460Sclaudio 	if ((buf = ibuf_open(len)) == NULL)
86*6b941460Sclaudio 		err(1, "ibuf_open(%zu)", len);
87*6b941460Sclaudio 
88*6b941460Sclaudio 	if (mrt_read_buf(fd, ibuf_reserve(buf, len), len) != len) {
89*6b941460Sclaudio 		ibuf_free(buf);
90*6b941460Sclaudio 		return (NULL);
91*6b941460Sclaudio 	}
92*6b941460Sclaudio 	return (buf);
93*6b941460Sclaudio }
94*6b941460Sclaudio 
95a20554fdSclaudio void
mrt_parse(int fd,struct mrt_parser * p,int verbose)96a20554fdSclaudio mrt_parse(int fd, struct mrt_parser *p, int verbose)
97a20554fdSclaudio {
98a20554fdSclaudio 	struct mrt_hdr		h;
99*6b941460Sclaudio 	struct mrt_bgp_state	s;
100*6b941460Sclaudio 	struct mrt_bgp_msg	m;
101a20554fdSclaudio 	struct mrt_peer		*pctx = NULL;
102a20554fdSclaudio 	struct mrt_rib		*r;
103*6b941460Sclaudio 	struct ibuf		*msg;
104a20554fdSclaudio 
105*6b941460Sclaudio 	while ((msg = mrt_read_msg(fd, &h)) != NULL) {
106*6b941460Sclaudio 		if (ibuf_size(msg) != ntohl(h.length))
107*6b941460Sclaudio 			errx(1, "corrupt message, %zu vs %u", ibuf_size(msg),
108*6b941460Sclaudio 			    ntohl(h.length));
109a20554fdSclaudio 		switch (ntohs(h.type)) {
110a20554fdSclaudio 		case MSG_NULL:
111a20554fdSclaudio 		case MSG_START:
112a20554fdSclaudio 		case MSG_DIE:
113a20554fdSclaudio 		case MSG_I_AM_DEAD:
114a20554fdSclaudio 		case MSG_PEER_DOWN:
115a20554fdSclaudio 		case MSG_PROTOCOL_BGP:
116a20554fdSclaudio 		case MSG_PROTOCOL_IDRP:
117a20554fdSclaudio 		case MSG_PROTOCOL_BGP4PLUS:
118a20554fdSclaudio 		case MSG_PROTOCOL_BGP4PLUS1:
119a20554fdSclaudio 			if (verbose)
120a20554fdSclaudio 				printf("deprecated MRT type %d\n",
121a20554fdSclaudio 				    ntohs(h.type));
122a20554fdSclaudio 			break;
123a20554fdSclaudio 		case MSG_PROTOCOL_RIP:
124a20554fdSclaudio 		case MSG_PROTOCOL_RIPNG:
125a20554fdSclaudio 		case MSG_PROTOCOL_OSPF:
126a20554fdSclaudio 		case MSG_PROTOCOL_ISIS_ET:
127a20554fdSclaudio 		case MSG_PROTOCOL_ISIS:
128a20554fdSclaudio 		case MSG_PROTOCOL_OSPFV3_ET:
129a20554fdSclaudio 		case MSG_PROTOCOL_OSPFV3:
130a20554fdSclaudio 			if (verbose)
1319c5d31d7Sjob 				printf("unsupported MRT type %d\n",
132a20554fdSclaudio 				    ntohs(h.type));
133a20554fdSclaudio 			break;
134a20554fdSclaudio 		case MSG_TABLE_DUMP:
135a20554fdSclaudio 			switch (ntohs(h.subtype)) {
136a20554fdSclaudio 			case MRT_DUMP_AFI_IP:
137a20554fdSclaudio 			case MRT_DUMP_AFI_IPv6:
138560ec76cSclaudio 				if (p->dump == NULL)
139560ec76cSclaudio 					break;
140a20554fdSclaudio 				if (mrt_parse_dump(&h, msg, &pctx, &r) == 0) {
141e86c4bdeSclaudio 					if (p->dump)
142a20554fdSclaudio 						p->dump(r, pctx, p->arg);
143a20554fdSclaudio 					mrt_free_rib(r);
144a20554fdSclaudio 				}
145a20554fdSclaudio 				break;
146a20554fdSclaudio 			default:
147a20554fdSclaudio 				if (verbose)
148a20554fdSclaudio 					printf("unknown AFI %d in table dump\n",
149a20554fdSclaudio 					    ntohs(h.subtype));
150a20554fdSclaudio 				break;
151a20554fdSclaudio 			}
152a20554fdSclaudio 			break;
153a20554fdSclaudio 		case MSG_TABLE_DUMP_V2:
154a20554fdSclaudio 			switch (ntohs(h.subtype)) {
155a20554fdSclaudio 			case MRT_DUMP_V2_PEER_INDEX_TABLE:
156560ec76cSclaudio 				if (p->dump == NULL)
157560ec76cSclaudio 					break;
158a20554fdSclaudio 				if (pctx)
159a20554fdSclaudio 					mrt_free_peers(pctx);
160a20554fdSclaudio 				pctx = mrt_parse_v2_peer(&h, msg);
161a20554fdSclaudio 				break;
162a20554fdSclaudio 			case MRT_DUMP_V2_RIB_IPV4_UNICAST:
163a20554fdSclaudio 			case MRT_DUMP_V2_RIB_IPV4_MULTICAST:
164a20554fdSclaudio 			case MRT_DUMP_V2_RIB_IPV6_UNICAST:
165a20554fdSclaudio 			case MRT_DUMP_V2_RIB_IPV6_MULTICAST:
166a20554fdSclaudio 			case MRT_DUMP_V2_RIB_GENERIC:
1679e59dee7Sclaudio 			case MRT_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH:
1689e59dee7Sclaudio 			case MRT_DUMP_V2_RIB_IPV4_MULTICAST_ADDPATH:
1699e59dee7Sclaudio 			case MRT_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH:
1709e59dee7Sclaudio 			case MRT_DUMP_V2_RIB_IPV6_MULTICAST_ADDPATH:
1719e59dee7Sclaudio 			case MRT_DUMP_V2_RIB_GENERIC_ADDPATH:
172560ec76cSclaudio 				if (p->dump == NULL)
173560ec76cSclaudio 					break;
174dcaecb8bSclaudio 				r = mrt_parse_v2_rib(&h, msg, verbose);
175a20554fdSclaudio 				if (r) {
176e86c4bdeSclaudio 					if (p->dump)
177a20554fdSclaudio 						p->dump(r, pctx, p->arg);
178a20554fdSclaudio 					mrt_free_rib(r);
179a20554fdSclaudio 				}
180a20554fdSclaudio 				break;
181a20554fdSclaudio 			default:
182a20554fdSclaudio 				if (verbose)
183000f4bc7Sclaudio 					printf("unhandled DUMP_V2 subtype %d\n",
184a20554fdSclaudio 					    ntohs(h.subtype));
185a20554fdSclaudio 				break;
186a20554fdSclaudio 			}
187a20554fdSclaudio 			break;
188a20554fdSclaudio 		case MSG_PROTOCOL_BGP4MP_ET:
189a20554fdSclaudio 		case MSG_PROTOCOL_BGP4MP:
190a20554fdSclaudio 			switch (ntohs(h.subtype)) {
191a20554fdSclaudio 			case BGP4MP_STATE_CHANGE:
192a20554fdSclaudio 			case BGP4MP_STATE_CHANGE_AS4:
193*6b941460Sclaudio 				if (mrt_parse_state(&s, &h, msg,
194*6b941460Sclaudio 				    verbose) != -1) {
195e86c4bdeSclaudio 					if (p->state)
196*6b941460Sclaudio 						p->state(&s, p->arg);
197e86c4bdeSclaudio 				}
198a20554fdSclaudio 				break;
199a20554fdSclaudio 			case BGP4MP_MESSAGE:
200a20554fdSclaudio 			case BGP4MP_MESSAGE_AS4:
201a20554fdSclaudio 			case BGP4MP_MESSAGE_LOCAL:
202a20554fdSclaudio 			case BGP4MP_MESSAGE_AS4_LOCAL:
2039e59dee7Sclaudio 			case BGP4MP_MESSAGE_ADDPATH:
2049e59dee7Sclaudio 			case BGP4MP_MESSAGE_AS4_ADDPATH:
2059e59dee7Sclaudio 			case BGP4MP_MESSAGE_LOCAL_ADDPATH:
2069e59dee7Sclaudio 			case BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH:
207*6b941460Sclaudio 				if (mrt_parse_msg(&m, &h, msg, verbose) != -1) {
208e86c4bdeSclaudio 					if (p->message)
209*6b941460Sclaudio 						p->message(&m, p->arg);
210e86c4bdeSclaudio 				}
211a20554fdSclaudio 				break;
212a20554fdSclaudio 			case BGP4MP_ENTRY:
213560ec76cSclaudio 				if (p->dump == NULL)
214560ec76cSclaudio 					break;
215dcaecb8bSclaudio 				if (mrt_parse_dump_mp(&h, msg, &pctx, &r,
216dcaecb8bSclaudio 				    verbose) == 0) {
217e86c4bdeSclaudio 					if (p->dump)
218a20554fdSclaudio 						p->dump(r, pctx, p->arg);
219a20554fdSclaudio 					mrt_free_rib(r);
220a20554fdSclaudio 				}
221a20554fdSclaudio 				break;
222a20554fdSclaudio 			default:
223a20554fdSclaudio 				if (verbose)
224a20554fdSclaudio 					printf("unhandled BGP4MP subtype %d\n",
225a20554fdSclaudio 					    ntohs(h.subtype));
226a20554fdSclaudio 				break;
227a20554fdSclaudio 			}
228a20554fdSclaudio 			break;
229a20554fdSclaudio 		default:
230a20554fdSclaudio 			if (verbose)
231a20554fdSclaudio 				printf("unknown MRT type %d\n", ntohs(h.type));
232a20554fdSclaudio 			break;
233a20554fdSclaudio 		}
234*6b941460Sclaudio 		ibuf_free(msg);
235a20554fdSclaudio 	}
236a20554fdSclaudio 	if (pctx)
237a20554fdSclaudio 		mrt_free_peers(pctx);
238a20554fdSclaudio }
239a20554fdSclaudio 
240dcaecb8bSclaudio static int
mrt_afi2aid(int afi,int safi,int verbose)241dcaecb8bSclaudio mrt_afi2aid(int afi, int safi, int verbose)
242dcaecb8bSclaudio {
243dcaecb8bSclaudio 	switch (afi) {
244dcaecb8bSclaudio 	case MRT_DUMP_AFI_IP:
245dcaecb8bSclaudio 		if (safi == -1 || safi == 1 || safi == 2)
246dcaecb8bSclaudio 			return AID_INET;
247dcaecb8bSclaudio 		else if (safi == 128)
248dcaecb8bSclaudio 			return AID_VPN_IPv4;
249dcaecb8bSclaudio 		break;
250dcaecb8bSclaudio 	case MRT_DUMP_AFI_IPv6:
251dcaecb8bSclaudio 		if (safi == -1 || safi == 1 || safi == 2)
252dcaecb8bSclaudio 			return AID_INET6;
253dcaecb8bSclaudio 		else if (safi == 128)
254dcaecb8bSclaudio 			return AID_VPN_IPv6;
255dcaecb8bSclaudio 		break;
256dcaecb8bSclaudio 	default:
257dcaecb8bSclaudio 		break;
258dcaecb8bSclaudio 	}
259dcaecb8bSclaudio 	if (verbose)
260dcaecb8bSclaudio 		printf("unhandled AFI/SAFI %d/%d\n", afi, safi);
261dcaecb8bSclaudio 	return AID_UNSPEC;
262dcaecb8bSclaudio }
263dcaecb8bSclaudio 
264a20554fdSclaudio struct mrt_peer *
mrt_parse_v2_peer(struct mrt_hdr * hdr,struct ibuf * msg)265*6b941460Sclaudio mrt_parse_v2_peer(struct mrt_hdr *hdr, struct ibuf *msg)
266a20554fdSclaudio {
267d5173905Sjsg 	struct mrt_peer_entry	*peers = NULL;
268a20554fdSclaudio 	struct mrt_peer	*p;
269*6b941460Sclaudio 	uint32_t	bid;
270*6b941460Sclaudio 	uint16_t	cnt, i;
271a20554fdSclaudio 
272*6b941460Sclaudio 	if (ibuf_size(msg) < 8)	/* min msg size */
273a20554fdSclaudio 		return NULL;
274a20554fdSclaudio 
275a20554fdSclaudio 	p = calloc(1, sizeof(struct mrt_peer));
276a20554fdSclaudio 	if (p == NULL)
277a20554fdSclaudio 		err(1, "calloc");
278a20554fdSclaudio 
279a20554fdSclaudio 	/* collector bgp id */
280*6b941460Sclaudio 	if (ibuf_get_n32(msg, &bid) == -1 ||
281*6b941460Sclaudio 	    ibuf_get_n16(msg, &cnt) == -1)
282*6b941460Sclaudio 		goto fail;
283a20554fdSclaudio 
284a20554fdSclaudio 	/* view name */
285a20554fdSclaudio 	if (cnt != 0) {
286a20554fdSclaudio 		if ((p->view = malloc(cnt + 1)) == NULL)
287a20554fdSclaudio 			err(1, "malloc");
288*6b941460Sclaudio 		if (ibuf_get(msg, p->view, cnt) == -1)
289*6b941460Sclaudio 			goto fail;
290a20554fdSclaudio 		p->view[cnt] = 0;
291a20554fdSclaudio 	} else
292a20554fdSclaudio 		if ((p->view = strdup("")) == NULL)
293a20554fdSclaudio 			err(1, "strdup");
294a20554fdSclaudio 
295a20554fdSclaudio 	/* peer_count */
296*6b941460Sclaudio 	if (ibuf_get_n16(msg, &cnt) == -1)
297a20554fdSclaudio 		goto fail;
298a20554fdSclaudio 
299a20554fdSclaudio 	/* peer entries */
300a20554fdSclaudio 	if ((peers = calloc(cnt, sizeof(struct mrt_peer_entry))) == NULL)
301a20554fdSclaudio 		err(1, "calloc");
302a20554fdSclaudio 	for (i = 0; i < cnt; i++) {
30359154960Sclaudio 		uint8_t type;
304a20554fdSclaudio 
305*6b941460Sclaudio 		if (ibuf_get_n8(msg, &type) == -1 ||
306*6b941460Sclaudio 		    ibuf_get_n32(msg, &peers[i].bgp_id) == -1)
307a20554fdSclaudio 			goto fail;
308a20554fdSclaudio 
309a20554fdSclaudio 		if (type & MRT_DUMP_V2_PEER_BIT_I) {
310*6b941460Sclaudio 			if (mrt_extract_addr(msg, &peers[i].addr,
311000f4bc7Sclaudio 			    AID_INET6) == -1)
312a20554fdSclaudio 				goto fail;
313a20554fdSclaudio 		} else {
314*6b941460Sclaudio 			if (mrt_extract_addr(msg, &peers[i].addr,
315000f4bc7Sclaudio 			    AID_INET) == -1)
316a20554fdSclaudio 				goto fail;
317a20554fdSclaudio 		}
318a20554fdSclaudio 
319a20554fdSclaudio 		if (type & MRT_DUMP_V2_PEER_BIT_A) {
320*6b941460Sclaudio 			if (ibuf_get_n32(msg, &peers[i].asnum) == -1)
321*6b941460Sclaudio 				goto fail;
322a20554fdSclaudio 		} else {
323*6b941460Sclaudio 			uint16_t as2;
324*6b941460Sclaudio 
325*6b941460Sclaudio 			if (ibuf_get_n16(msg, &as2) == -1)
326*6b941460Sclaudio 				goto fail;
327*6b941460Sclaudio 			peers[i].asnum = as2;
328a20554fdSclaudio 		}
329a20554fdSclaudio 	}
330a20554fdSclaudio 	p->peers = peers;
331a20554fdSclaudio 	p->npeers = cnt;
332a20554fdSclaudio 	return (p);
333a20554fdSclaudio fail:
334a20554fdSclaudio 	mrt_free_peers(p);
335d5173905Sjsg 	free(peers);
336a20554fdSclaudio 	return (NULL);
337a20554fdSclaudio }
338a20554fdSclaudio 
339a20554fdSclaudio struct mrt_rib *
mrt_parse_v2_rib(struct mrt_hdr * hdr,struct ibuf * msg,int verbose)340*6b941460Sclaudio mrt_parse_v2_rib(struct mrt_hdr *hdr, struct ibuf *msg, int verbose)
341a20554fdSclaudio {
342d5173905Sjsg 	struct mrt_rib_entry *entries = NULL;
343a20554fdSclaudio 	struct mrt_rib	*r;
344*6b941460Sclaudio 	uint16_t	i, afi;
34559154960Sclaudio 	uint8_t		safi, aid;
346a20554fdSclaudio 
347a20554fdSclaudio 	r = calloc(1, sizeof(struct mrt_rib));
348a20554fdSclaudio 	if (r == NULL)
349a20554fdSclaudio 		err(1, "calloc");
350a20554fdSclaudio 
351a20554fdSclaudio 	/* seq_num */
352*6b941460Sclaudio 	if (ibuf_get_n32(msg, &r->seqnum) == -1)
353*6b941460Sclaudio 		goto fail;
354a20554fdSclaudio 
355a20554fdSclaudio 	switch (ntohs(hdr->subtype)) {
3569e59dee7Sclaudio 	case MRT_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH:
3579e59dee7Sclaudio 	case MRT_DUMP_V2_RIB_IPV4_MULTICAST_ADDPATH:
3589e59dee7Sclaudio 		r->add_path = 1;
3599e59dee7Sclaudio 		/* FALLTHROUGH */
360a20554fdSclaudio 	case MRT_DUMP_V2_RIB_IPV4_UNICAST:
361a20554fdSclaudio 	case MRT_DUMP_V2_RIB_IPV4_MULTICAST:
362dcaecb8bSclaudio 		/* prefix */
363*6b941460Sclaudio 		if (mrt_extract_prefix(msg, AID_INET, &r->prefix,
364*6b941460Sclaudio 		    &r->prefixlen, verbose) == -1)
365a20554fdSclaudio 			goto fail;
366a20554fdSclaudio 		break;
3679e59dee7Sclaudio 	case MRT_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH:
3689e59dee7Sclaudio 	case MRT_DUMP_V2_RIB_IPV6_MULTICAST_ADDPATH:
3699e59dee7Sclaudio 		r->add_path = 1;
3709e59dee7Sclaudio 		/* FALLTHROUGH */
371a20554fdSclaudio 	case MRT_DUMP_V2_RIB_IPV6_UNICAST:
372a20554fdSclaudio 	case MRT_DUMP_V2_RIB_IPV6_MULTICAST:
373dcaecb8bSclaudio 		/* prefix */
374*6b941460Sclaudio 		if (mrt_extract_prefix(msg, AID_INET6, &r->prefix,
375*6b941460Sclaudio 		    &r->prefixlen, verbose) == -1)
376a20554fdSclaudio 			goto fail;
377a20554fdSclaudio 		break;
3789e59dee7Sclaudio 	case MRT_DUMP_V2_RIB_GENERIC_ADDPATH:
3799ad3d757Sclaudio 		/*
3809ad3d757Sclaudio 		 * RFC8050 handling for add-path has special handling for
3819ad3d757Sclaudio 		 * RIB_GENERIC_ADDPATH but nobody implements it that way.
3829ad3d757Sclaudio 		 * So just use the same way as for the other _ADDPATH types.
3839ad3d757Sclaudio 		 */
3849e59dee7Sclaudio 		r->add_path = 1;
3859e59dee7Sclaudio 		/* FALLTHROUGH */
386a20554fdSclaudio 	case MRT_DUMP_V2_RIB_GENERIC:
387dcaecb8bSclaudio 		/* fetch AFI/SAFI pair */
388*6b941460Sclaudio 		if (ibuf_get_n16(msg, &afi) == -1 ||
389*6b941460Sclaudio 		    ibuf_get_n8(msg, &safi) == -1)
3909e59dee7Sclaudio 			goto fail;
391dcaecb8bSclaudio 
392dcaecb8bSclaudio 		if ((aid = mrt_afi2aid(afi, safi, verbose)) == AID_UNSPEC)
393a20554fdSclaudio 			goto fail;
394dcaecb8bSclaudio 
395dcaecb8bSclaudio 		/* prefix */
396*6b941460Sclaudio 		if (mrt_extract_prefix(msg, aid, &r->prefix,
397*6b941460Sclaudio 		    &r->prefixlen, verbose) == -1)
398dcaecb8bSclaudio 			goto fail;
399dcaecb8bSclaudio 		break;
40071077332Sclaudio 	default:
4019c5d31d7Sjob 		errx(1, "unknown subtype %hd", ntohs(hdr->subtype));
402a20554fdSclaudio 	}
403a20554fdSclaudio 
404a20554fdSclaudio 	/* entries count */
405*6b941460Sclaudio 	if (ibuf_get_n16(msg, &r->nentries) == -1)
406a20554fdSclaudio 		goto fail;
407a20554fdSclaudio 
408a20554fdSclaudio 	/* entries */
409*6b941460Sclaudio 	if ((entries = calloc(r->nentries, sizeof(struct mrt_rib_entry))) ==
410*6b941460Sclaudio 	    NULL)
411a20554fdSclaudio 		err(1, "calloc");
412*6b941460Sclaudio 	for (i = 0; i < r->nentries; i++) {
413*6b941460Sclaudio 		struct ibuf	abuf;
41459154960Sclaudio 		uint32_t	otm;
415*6b941460Sclaudio 		uint16_t	alen;
416*6b941460Sclaudio 
417a20554fdSclaudio 		/* peer index */
418*6b941460Sclaudio 		if (ibuf_get_n16(msg, &entries[i].peer_idx) == -1)
419*6b941460Sclaudio 			goto fail;
420a20554fdSclaudio 
421a20554fdSclaudio 		/* originated */
422*6b941460Sclaudio 		if (ibuf_get_n32(msg, &otm) == -1)
423*6b941460Sclaudio 			goto fail;
424*6b941460Sclaudio 		entries[i].originated = otm;
425a20554fdSclaudio 
4269ad3d757Sclaudio 		if (r->add_path) {
427*6b941460Sclaudio 			if (ibuf_get_n32(msg, &entries[i].path_id) == -1)
4289e59dee7Sclaudio 				goto fail;
4299e59dee7Sclaudio 		}
4309e59dee7Sclaudio 
431a20554fdSclaudio 		/* attr_len */
432*6b941460Sclaudio 		if (ibuf_get_n16(msg, &alen) == -1 ||
433*6b941460Sclaudio 		    ibuf_get_ibuf(msg, alen, &abuf) == -1)
434*6b941460Sclaudio 			goto fail;
435a20554fdSclaudio 
436a20554fdSclaudio 		/* attr */
437*6b941460Sclaudio 		if (mrt_extract_attr(&entries[i], &abuf, r->prefix.aid,
438*6b941460Sclaudio 		    1) == -1)
439a20554fdSclaudio 			goto fail;
440a20554fdSclaudio 	}
441a20554fdSclaudio 	r->entries = entries;
442a20554fdSclaudio 	return (r);
443a20554fdSclaudio fail:
444a20554fdSclaudio 	mrt_free_rib(r);
445d5173905Sjsg 	free(entries);
446a20554fdSclaudio 	return (NULL);
447a20554fdSclaudio }
448a20554fdSclaudio 
449a20554fdSclaudio int
mrt_parse_dump(struct mrt_hdr * hdr,struct ibuf * msg,struct mrt_peer ** pp,struct mrt_rib ** rp)450*6b941460Sclaudio mrt_parse_dump(struct mrt_hdr *hdr, struct ibuf *msg, struct mrt_peer **pp,
451a20554fdSclaudio     struct mrt_rib **rp)
452a20554fdSclaudio {
453*6b941460Sclaudio 	struct ibuf		 abuf;
454a20554fdSclaudio 	struct mrt_peer		*p;
455a20554fdSclaudio 	struct mrt_rib		*r;
456a20554fdSclaudio 	struct mrt_rib_entry	*re;
457*6b941460Sclaudio 	uint32_t		 tmp32;
458*6b941460Sclaudio 	uint16_t		 tmp16, alen;
459a20554fdSclaudio 
460a20554fdSclaudio 	if (*pp == NULL) {
461a20554fdSclaudio 		*pp = calloc(1, sizeof(struct mrt_peer));
462a20554fdSclaudio 		if (*pp == NULL)
463a20554fdSclaudio 			err(1, "calloc");
464a20554fdSclaudio 		(*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry));
465a20554fdSclaudio 		if ((*pp)->peers == NULL)
466a20554fdSclaudio 			err(1, "calloc");
467a20554fdSclaudio 		(*pp)->npeers = 1;
468a20554fdSclaudio 	}
469a20554fdSclaudio 	p = *pp;
470a20554fdSclaudio 
471a20554fdSclaudio 	*rp = r = calloc(1, sizeof(struct mrt_rib));
472a20554fdSclaudio 	if (r == NULL)
473a20554fdSclaudio 		err(1, "calloc");
474a20554fdSclaudio 	re = calloc(1, sizeof(struct mrt_rib_entry));
475a20554fdSclaudio 	if (re == NULL)
476a20554fdSclaudio 		err(1, "calloc");
477a20554fdSclaudio 	r->nentries = 1;
478a20554fdSclaudio 	r->entries = re;
479a20554fdSclaudio 
480*6b941460Sclaudio 	if (ibuf_skip(msg, sizeof(uint16_t)) == -1 ||	/* view */
481*6b941460Sclaudio 	    ibuf_get_n16(msg, &tmp16) == -1)		/* seqnum */
482a20554fdSclaudio 		goto fail;
483*6b941460Sclaudio 	r->seqnum = tmp16;
484a20554fdSclaudio 
485a20554fdSclaudio 	switch (ntohs(hdr->subtype)) {
486a20554fdSclaudio 	case MRT_DUMP_AFI_IP:
487*6b941460Sclaudio 		if (mrt_extract_addr(msg, &r->prefix, AID_INET) == -1)
488a20554fdSclaudio 			goto fail;
489a20554fdSclaudio 		break;
490a20554fdSclaudio 	case MRT_DUMP_AFI_IPv6:
491*6b941460Sclaudio 		if (mrt_extract_addr(msg, &r->prefix, AID_INET6) == -1)
492a20554fdSclaudio 			goto fail;
493a20554fdSclaudio 		break;
494a20554fdSclaudio 	}
495*6b941460Sclaudio 	if (ibuf_get_n8(msg, &r->prefixlen) == -1 ||	/* prefixlen */
496*6b941460Sclaudio 	    ibuf_skip(msg, 1) == -1 ||			/* status */
497*6b941460Sclaudio 	    ibuf_get_n32(msg, &tmp32) == -1)		/* originated */
498a20554fdSclaudio 		goto fail;
499*6b941460Sclaudio 	re->originated = tmp32;
500a20554fdSclaudio 	/* peer ip */
501a20554fdSclaudio 	switch (ntohs(hdr->subtype)) {
502a20554fdSclaudio 	case MRT_DUMP_AFI_IP:
503*6b941460Sclaudio 		if (mrt_extract_addr(msg, &p->peers->addr, AID_INET) == -1)
504a20554fdSclaudio 			goto fail;
505a20554fdSclaudio 		break;
506a20554fdSclaudio 	case MRT_DUMP_AFI_IPv6:
507*6b941460Sclaudio 		if (mrt_extract_addr(msg, &p->peers->addr, AID_INET6) == -1)
508a20554fdSclaudio 			goto fail;
509a20554fdSclaudio 		break;
510a20554fdSclaudio 	}
511*6b941460Sclaudio 	if (ibuf_get_n16(msg, &tmp16) == -1)
512*6b941460Sclaudio 		goto fail;
513*6b941460Sclaudio 	p->peers->asnum = tmp16;
514a20554fdSclaudio 
515*6b941460Sclaudio 	if (ibuf_get_n16(msg, &alen) == -1 ||
516*6b941460Sclaudio 	    ibuf_get_ibuf(msg, alen, &abuf) == -1)
517*6b941460Sclaudio 		goto fail;
518a20554fdSclaudio 
519a20554fdSclaudio 	/* attr */
520*6b941460Sclaudio 	if (mrt_extract_attr(re, &abuf, r->prefix.aid, 0) == -1)
521a20554fdSclaudio 		goto fail;
522a20554fdSclaudio 	return (0);
523a20554fdSclaudio fail:
524a20554fdSclaudio 	mrt_free_rib(r);
525a20554fdSclaudio 	return (-1);
526a20554fdSclaudio }
527a20554fdSclaudio 
528a20554fdSclaudio int
mrt_parse_dump_mp(struct mrt_hdr * hdr,struct ibuf * msg,struct mrt_peer ** pp,struct mrt_rib ** rp,int verbose)529*6b941460Sclaudio mrt_parse_dump_mp(struct mrt_hdr *hdr, struct ibuf *msg, struct mrt_peer **pp,
530dcaecb8bSclaudio     struct mrt_rib **rp, int verbose)
531a20554fdSclaudio {
532*6b941460Sclaudio 	struct ibuf		 abuf;
533a20554fdSclaudio 	struct mrt_peer		*p;
534a20554fdSclaudio 	struct mrt_rib		*r;
535a20554fdSclaudio 	struct mrt_rib_entry	*re;
536*6b941460Sclaudio 	uint32_t		 tmp32;
53759154960Sclaudio 	uint16_t		 asnum, alen, afi;
53859154960Sclaudio 	uint8_t			 safi, nhlen, aid;
53997d44d7cShenning 
540a20554fdSclaudio 	if (*pp == NULL) {
541a20554fdSclaudio 		*pp = calloc(1, sizeof(struct mrt_peer));
542a20554fdSclaudio 		if (*pp == NULL)
543a20554fdSclaudio 			err(1, "calloc");
544a20554fdSclaudio 		(*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry));
545a20554fdSclaudio 		if ((*pp)->peers == NULL)
546a20554fdSclaudio 			err(1, "calloc");
547a20554fdSclaudio 		(*pp)->npeers = 1;
548a20554fdSclaudio 	}
549a20554fdSclaudio 	p = *pp;
550a20554fdSclaudio 
551a20554fdSclaudio 	*rp = r = calloc(1, sizeof(struct mrt_rib));
552a20554fdSclaudio 	if (r == NULL)
553a20554fdSclaudio 		err(1, "calloc");
554a20554fdSclaudio 	re = calloc(1, sizeof(struct mrt_rib_entry));
555a20554fdSclaudio 	if (re == NULL)
556a20554fdSclaudio 		err(1, "calloc");
557a20554fdSclaudio 	r->nentries = 1;
558a20554fdSclaudio 	r->entries = re;
559a20554fdSclaudio 
560*6b941460Sclaudio 	/* just ignore the microsec field for _ET header for now */
561*6b941460Sclaudio 	if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) {
562*6b941460Sclaudio 		if (ibuf_skip(msg, sizeof(uint32_t)) == -1)
563a20554fdSclaudio 			goto fail;
564*6b941460Sclaudio 	}
565*6b941460Sclaudio 
566*6b941460Sclaudio 	if (ibuf_skip(msg, sizeof(uint16_t)) == -1 ||	/* source AS */
567*6b941460Sclaudio 	    ibuf_get_n16(msg, &asnum) == -1 ||		/* dest AS */
568*6b941460Sclaudio 	    ibuf_skip(msg, sizeof(uint16_t)) == -1 ||	/* iface index */
569*6b941460Sclaudio 	    ibuf_get_n16(msg, &afi) == -1)
570*6b941460Sclaudio 		goto fail;
571*6b941460Sclaudio 	p->peers->asnum = asnum;
572a20554fdSclaudio 
573a20554fdSclaudio 	/* source + dest ip */
574a20554fdSclaudio 	switch (afi) {
575a20554fdSclaudio 	case MRT_DUMP_AFI_IP:
576a20554fdSclaudio 		/* source IP */
577*6b941460Sclaudio 		if (ibuf_skip(msg, sizeof(struct in_addr)) == -1)
578560ec76cSclaudio 			goto fail;
579*6b941460Sclaudio 		/* dest IP */
580*6b941460Sclaudio 		if (mrt_extract_addr(msg, &p->peers->addr, AID_INET) == -1)
581*6b941460Sclaudio 			goto fail;
582a20554fdSclaudio 		break;
583a20554fdSclaudio 	case MRT_DUMP_AFI_IPv6:
584a20554fdSclaudio 		/* source IP */
585*6b941460Sclaudio 		if (ibuf_skip(msg, sizeof(struct in6_addr)) == -1)
586560ec76cSclaudio 			goto fail;
587*6b941460Sclaudio 		/* dest IP */
588*6b941460Sclaudio 		if (mrt_extract_addr(msg, &p->peers->addr, AID_INET6) == -1)
589*6b941460Sclaudio 			goto fail;
590a20554fdSclaudio 		break;
591a20554fdSclaudio 	}
592a20554fdSclaudio 
593*6b941460Sclaudio 	if (ibuf_skip(msg, sizeof(uint16_t)) == -1 ||	/* view */
594*6b941460Sclaudio 	    ibuf_skip(msg, sizeof(uint16_t)) == -1 ||	/* status */
595*6b941460Sclaudio 	    ibuf_get_n32(msg, &tmp32) == -1)		/* originated */
596a20554fdSclaudio 		goto fail;
597*6b941460Sclaudio 	re->originated = tmp32;
598a20554fdSclaudio 
599*6b941460Sclaudio 	if (ibuf_get_n16(msg, &afi) == -1 ||		/* afi */
600*6b941460Sclaudio 	    ibuf_get_n8(msg, &safi) == -1)		/* safi */
601*6b941460Sclaudio 		goto fail;
602dcaecb8bSclaudio 	if ((aid = mrt_afi2aid(afi, safi, verbose)) == AID_UNSPEC)
603a20554fdSclaudio 		goto fail;
604a20554fdSclaudio 
605*6b941460Sclaudio 	if (ibuf_get_n8(msg, &nhlen) == -1)		/* nhlen */
606*6b941460Sclaudio 		goto fail;
607a20554fdSclaudio 
608a20554fdSclaudio 	/* nexthop */
609*6b941460Sclaudio 	if (mrt_extract_addr(msg, &re->nexthop, aid) == -1)
610a20554fdSclaudio 		goto fail;
611a20554fdSclaudio 
612a20554fdSclaudio 	/* prefix */
613*6b941460Sclaudio 	if (mrt_extract_prefix(msg, aid, &r->prefix, &r->prefixlen,
614*6b941460Sclaudio 	    verbose) == -1)
615a20554fdSclaudio 		goto fail;
616a20554fdSclaudio 
617*6b941460Sclaudio 	if (ibuf_get_n16(msg, &alen) == -1 ||
618*6b941460Sclaudio 	    ibuf_get_ibuf(msg, alen, &abuf) == -1)
619a20554fdSclaudio 		goto fail;
620*6b941460Sclaudio 	if (mrt_extract_attr(re, &abuf, r->prefix.aid, 0) == -1)
621a20554fdSclaudio 		goto fail;
622a20554fdSclaudio 
623a20554fdSclaudio 	return (0);
624a20554fdSclaudio fail:
625a20554fdSclaudio 	mrt_free_rib(r);
626a20554fdSclaudio 	return (-1);
627a20554fdSclaudio }
628a20554fdSclaudio 
629a20554fdSclaudio int
mrt_extract_attr(struct mrt_rib_entry * re,struct ibuf * buf,uint8_t aid,int as4)630*6b941460Sclaudio mrt_extract_attr(struct mrt_rib_entry *re, struct ibuf *buf, uint8_t aid,
631a20554fdSclaudio     int as4)
632a20554fdSclaudio {
633*6b941460Sclaudio 	struct ibuf	abuf;
634a20554fdSclaudio 	struct mrt_attr	*ap;
635*6b941460Sclaudio 	size_t		alen, hlen;
636*6b941460Sclaudio 	uint8_t		type, flags;
637a20554fdSclaudio 
638a20554fdSclaudio 	do {
639*6b941460Sclaudio 		ibuf_from_ibuf(&abuf, buf);
640*6b941460Sclaudio 		if (ibuf_get_n8(&abuf, &flags) == -1 ||
641*6b941460Sclaudio 		    ibuf_get_n8(&abuf, &type) == -1)
642a20554fdSclaudio 			return (-1);
643a20554fdSclaudio 
644a20554fdSclaudio 		if (flags & MRT_ATTR_EXTLEN) {
645*6b941460Sclaudio 			uint16_t tmp16;
646*6b941460Sclaudio 			if (ibuf_get_n16(&abuf, &tmp16) == -1)
647a20554fdSclaudio 				return (-1);
648*6b941460Sclaudio 			alen = tmp16;
649*6b941460Sclaudio 			hlen = 4;
650a20554fdSclaudio 		} else {
651*6b941460Sclaudio 			uint8_t tmp8;
652*6b941460Sclaudio 			if (ibuf_get_n8(&abuf, &tmp8) == -1)
653*6b941460Sclaudio 				return (-1);
654*6b941460Sclaudio 			alen = tmp8;
655*6b941460Sclaudio 			hlen = 3;
656a20554fdSclaudio 		}
657*6b941460Sclaudio 		if (ibuf_truncate(&abuf, alen) == -1)
658*6b941460Sclaudio 			return (-1);
659*6b941460Sclaudio 		/* consume the attribute in buf before moving forward */
660*6b941460Sclaudio 		if (ibuf_skip(buf, hlen + alen) == -1)
661*6b941460Sclaudio 			return (-1);
662*6b941460Sclaudio 
663a20554fdSclaudio 		switch (type) {
664a20554fdSclaudio 		case MRT_ATTR_ORIGIN:
665*6b941460Sclaudio 			if (alen != 1)
666a20554fdSclaudio 				return (-1);
667*6b941460Sclaudio 			if (ibuf_get_n8(&abuf, &re->origin) == -1)
668*6b941460Sclaudio 				return (-1);
669a20554fdSclaudio 			break;
670a20554fdSclaudio 		case MRT_ATTR_ASPATH:
671a20554fdSclaudio 			if (as4) {
672*6b941460Sclaudio 				re->aspath_len = alen;
673*6b941460Sclaudio 				if ((re->aspath = malloc(alen)) == NULL)
674a20554fdSclaudio 					err(1, "malloc");
675*6b941460Sclaudio 				if (ibuf_get(&abuf, re->aspath, alen) == -1)
676*6b941460Sclaudio 					return (-1);
677a20554fdSclaudio 			} else {
678*6b941460Sclaudio 				re->aspath = mrt_aspath_inflate(&abuf,
679a20554fdSclaudio 				    &re->aspath_len);
680a20554fdSclaudio 				if (re->aspath == NULL)
681a20554fdSclaudio 					return (-1);
682a20554fdSclaudio 			}
683a20554fdSclaudio 			break;
684a20554fdSclaudio 		case MRT_ATTR_NEXTHOP:
685*6b941460Sclaudio 			if (alen != 4)
686a20554fdSclaudio 				return (-1);
687000f4bc7Sclaudio 			if (aid != AID_INET)
688a20554fdSclaudio 				break;
689*6b941460Sclaudio 			if (ibuf_get(&abuf, &re->nexthop.v4,
690*6b941460Sclaudio 			    sizeof(re->nexthop.v4)) == -1)
691*6b941460Sclaudio 				return (-1);
692000f4bc7Sclaudio 			re->nexthop.aid = AID_INET;
693a20554fdSclaudio 			break;
694a20554fdSclaudio 		case MRT_ATTR_MED:
695*6b941460Sclaudio 			if (alen != 4)
696a20554fdSclaudio 				return (-1);
697*6b941460Sclaudio 			if (ibuf_get_n32(&abuf, &re->med) == -1)
698*6b941460Sclaudio 				return (-1);
699a20554fdSclaudio 			break;
700a20554fdSclaudio 		case MRT_ATTR_LOCALPREF:
701*6b941460Sclaudio 			if (alen != 4)
702a20554fdSclaudio 				return (-1);
703*6b941460Sclaudio 			if (ibuf_get_n32(&abuf, &re->local_pref) == -1)
704*6b941460Sclaudio 				return (-1);
705a20554fdSclaudio 			break;
706a20554fdSclaudio 		case MRT_ATTR_MP_REACH_NLRI:
707a20554fdSclaudio 			/*
708a20554fdSclaudio 			 * XXX horrible hack:
709a20554fdSclaudio 			 * Once again IETF and the real world differ in the
71059cf237eSclaudio 			 * implementation. In short the abbreviated MP_NLRI
71159cf237eSclaudio 			 * hack in the standard is not used in real life.
712a20554fdSclaudio 			 * Detect the two cases by looking at the first byte
71359cf237eSclaudio 			 * of the payload (either the nexthop addr length (RFC)
71459cf237eSclaudio 			 * or the high byte of the AFI (old form)). If the
71559cf237eSclaudio 			 * first byte matches the expected nexthop length it
71659cf237eSclaudio 			 * is expected to be the RFC 6396 encoding.
717*6b941460Sclaudio 			 *
718*6b941460Sclaudio 			 * Checking for the hack skips over the nhlen.
719a20554fdSclaudio 			 */
720*6b941460Sclaudio 			{
721*6b941460Sclaudio 				uint8_t	hack;
722*6b941460Sclaudio 				if (ibuf_get_n8(&abuf, &hack) == -1)
723*6b941460Sclaudio 					return (-1);
724*6b941460Sclaudio 				if (hack != alen - 1) {
725*6b941460Sclaudio 					if (ibuf_skip(&abuf, 3) == -1)
726*6b941460Sclaudio 						return (-1);
727*6b941460Sclaudio 				}
728a20554fdSclaudio 			}
729000f4bc7Sclaudio 			switch (aid) {
730000f4bc7Sclaudio 			case AID_INET6:
731*6b941460Sclaudio 				if (ibuf_get(&abuf, &re->nexthop.v6,
732*6b941460Sclaudio 				    sizeof(re->nexthop.v6)) == -1)
733a20554fdSclaudio 					return (-1);
734000f4bc7Sclaudio 				re->nexthop.aid = aid;
735a20554fdSclaudio 				break;
736000f4bc7Sclaudio 			case AID_VPN_IPv4:
737*6b941460Sclaudio 				if (ibuf_skip(&abuf, sizeof(uint64_t)) == -1 ||
738*6b941460Sclaudio 				    ibuf_get(&abuf, &re->nexthop.v4,
739*6b941460Sclaudio 				    sizeof(re->nexthop.v4)) == -1)
740a20554fdSclaudio 					return (-1);
741000f4bc7Sclaudio 				re->nexthop.aid = aid;
742000f4bc7Sclaudio 				break;
743000f4bc7Sclaudio 			case AID_VPN_IPv6:
744*6b941460Sclaudio 				if (ibuf_skip(&abuf, sizeof(uint64_t)) == -1 ||
745*6b941460Sclaudio 				    ibuf_get(&abuf, &re->nexthop.v6,
746*6b941460Sclaudio 				    sizeof(re->nexthop.v6)) == -1)
747dcaecb8bSclaudio 					return (-1);
748dcaecb8bSclaudio 				re->nexthop.aid = aid;
749a20554fdSclaudio 				break;
750a20554fdSclaudio 			}
751a20554fdSclaudio 			break;
752a20554fdSclaudio 		case MRT_ATTR_AS4PATH:
753a20554fdSclaudio 			if (!as4) {
754a20554fdSclaudio 				free(re->aspath);
755*6b941460Sclaudio 				re->aspath_len = alen;
756*6b941460Sclaudio 				if ((re->aspath = malloc(alen)) == NULL)
757a20554fdSclaudio 					err(1, "malloc");
758*6b941460Sclaudio 				if (ibuf_get(&abuf, re->aspath, alen) == -1)
759*6b941460Sclaudio 					return (-1);
760a20554fdSclaudio 				break;
761a20554fdSclaudio 			}
762a20554fdSclaudio 			/* FALLTHROUGH */
763a20554fdSclaudio 		default:
764a20554fdSclaudio 			re->nattrs++;
765a20554fdSclaudio 			if (re->nattrs >= UCHAR_MAX)
766a20554fdSclaudio 				err(1, "too many attributes");
767b795643eSderaadt 			ap = reallocarray(re->attrs,
768b795643eSderaadt 			    re->nattrs, sizeof(struct mrt_attr));
769a20554fdSclaudio 			if (ap == NULL)
770a20554fdSclaudio 				err(1, "realloc");
771a20554fdSclaudio 			re->attrs = ap;
772a20554fdSclaudio 			ap = re->attrs + re->nattrs - 1;
773*6b941460Sclaudio 			ibuf_rewind(&abuf);
774*6b941460Sclaudio 			ap->attr_len = ibuf_size(&abuf);
775a20554fdSclaudio 			if ((ap->attr = malloc(ap->attr_len)) == NULL)
776a20554fdSclaudio 				err(1, "malloc");
777*6b941460Sclaudio 			if (ibuf_get(&abuf, ap->attr, ap->attr_len) == -1)
778*6b941460Sclaudio 				return (-1);
779a20554fdSclaudio 			break;
780a20554fdSclaudio 		}
781*6b941460Sclaudio 	} while (ibuf_size(buf) > 0);
782a20554fdSclaudio 
783a20554fdSclaudio 	return (0);
784a20554fdSclaudio }
785a20554fdSclaudio 
786a20554fdSclaudio void
mrt_free_peers(struct mrt_peer * p)787a20554fdSclaudio mrt_free_peers(struct mrt_peer *p)
788a20554fdSclaudio {
789a20554fdSclaudio 	free(p->peers);
790a20554fdSclaudio 	free(p->view);
791a20554fdSclaudio 	free(p);
792a20554fdSclaudio }
793a20554fdSclaudio 
794a20554fdSclaudio void
mrt_free_rib(struct mrt_rib * r)795a20554fdSclaudio mrt_free_rib(struct mrt_rib *r)
796a20554fdSclaudio {
79759154960Sclaudio 	uint16_t	i, j;
798a20554fdSclaudio 
799a20554fdSclaudio 	for (i = 0; i < r->nentries && r->entries; i++) {
800a20554fdSclaudio 		for (j = 0; j < r->entries[i].nattrs; j++)
801a20554fdSclaudio 			 free(r->entries[i].attrs[j].attr);
802a20554fdSclaudio 		free(r->entries[i].attrs);
803a20554fdSclaudio 		free(r->entries[i].aspath);
804a20554fdSclaudio 	}
805a20554fdSclaudio 
806a20554fdSclaudio 	free(r->entries);
807a20554fdSclaudio 	free(r);
808a20554fdSclaudio }
809a20554fdSclaudio 
810a20554fdSclaudio u_char *
mrt_aspath_inflate(struct ibuf * buf,uint16_t * newlen)811*6b941460Sclaudio mrt_aspath_inflate(struct ibuf *buf, uint16_t *newlen)
812a20554fdSclaudio {
813*6b941460Sclaudio 	struct ibuf *asbuf;
814*6b941460Sclaudio 	u_char *data;
815*6b941460Sclaudio 	size_t len;
816a20554fdSclaudio 
817*6b941460Sclaudio 	*newlen = 0;
818*6b941460Sclaudio 	asbuf = aspath_inflate(buf);
819*6b941460Sclaudio 	if (asbuf == NULL)
820a20554fdSclaudio 		return NULL;
821a20554fdSclaudio 
822*6b941460Sclaudio 	len = ibuf_size(asbuf);
823*6b941460Sclaudio 	if ((data = malloc(len)) == NULL)
824a20554fdSclaudio 		err(1, "malloc");
825*6b941460Sclaudio 	if (ibuf_get(asbuf, data, len) == -1) {
826*6b941460Sclaudio 		ibuf_free(asbuf);
827*6b941460Sclaudio 		return (NULL);
828a20554fdSclaudio 	}
829*6b941460Sclaudio 	ibuf_free(asbuf);
830*6b941460Sclaudio 	*newlen = len;
831*6b941460Sclaudio 	return (data);
832a20554fdSclaudio }
833560ec76cSclaudio 
834560ec76cSclaudio int
mrt_extract_addr(struct ibuf * msg,struct bgpd_addr * addr,uint8_t aid)835*6b941460Sclaudio mrt_extract_addr(struct ibuf *msg, struct bgpd_addr *addr, uint8_t aid)
836560ec76cSclaudio {
837000f4bc7Sclaudio 	memset(addr, 0, sizeof(*addr));
838000f4bc7Sclaudio 	switch (aid) {
839000f4bc7Sclaudio 	case AID_INET:
840*6b941460Sclaudio 		if (ibuf_get(msg, &addr->v4, sizeof(addr->v4)) == -1)
841560ec76cSclaudio 			return (-1);
842*6b941460Sclaudio 		break;
843000f4bc7Sclaudio 	case AID_INET6:
844*6b941460Sclaudio 		if (ibuf_get(msg, &addr->v6, sizeof(addr->v6)) == -1)
845560ec76cSclaudio 			return (-1);
846*6b941460Sclaudio 		break;
847000f4bc7Sclaudio 	case AID_VPN_IPv4:
848000f4bc7Sclaudio 		/* XXX labelstack and rd missing */
849*6b941460Sclaudio 		if (ibuf_skip(msg, sizeof(uint64_t)) == -1 ||
850*6b941460Sclaudio 		    ibuf_get(msg, &addr->v4, sizeof(addr->v4)) == -1)
851*6b941460Sclaudio 			return (-1);
852*6b941460Sclaudio 		break;
853000f4bc7Sclaudio 	case AID_VPN_IPv6:
854000f4bc7Sclaudio 		/* XXX labelstack and rd missing */
855*6b941460Sclaudio 		if (ibuf_skip(msg, sizeof(uint64_t)) == -1 ||
856*6b941460Sclaudio 		    ibuf_get(msg, &addr->v6, sizeof(addr->v6)) == -1)
857*6b941460Sclaudio 			return (-1);
858*6b941460Sclaudio 		break;
859560ec76cSclaudio 	default:
860560ec76cSclaudio 		return (-1);
861560ec76cSclaudio 	}
862*6b941460Sclaudio 	addr->aid = aid;
863*6b941460Sclaudio 	return 0;
864560ec76cSclaudio }
865e86c4bdeSclaudio 
866dcaecb8bSclaudio int
mrt_extract_prefix(struct ibuf * msg,uint8_t aid,struct bgpd_addr * prefix,uint8_t * prefixlen,int verbose)867*6b941460Sclaudio mrt_extract_prefix(struct ibuf *msg, uint8_t aid, struct bgpd_addr *prefix,
868*6b941460Sclaudio     uint8_t *prefixlen, int verbose)
869dcaecb8bSclaudio {
870dcaecb8bSclaudio 	int r;
871dcaecb8bSclaudio 
872dcaecb8bSclaudio 	switch (aid) {
873dcaecb8bSclaudio 	case AID_INET:
8745ad4fcbaSclaudio 		r = nlri_get_prefix(msg, prefix, prefixlen);
875dcaecb8bSclaudio 		break;
876dcaecb8bSclaudio 	case AID_INET6:
8775ad4fcbaSclaudio 		r = nlri_get_prefix6(msg, prefix, prefixlen);
878dcaecb8bSclaudio 		break;
879dcaecb8bSclaudio 	case AID_VPN_IPv4:
8805ad4fcbaSclaudio 		r = nlri_get_vpn4(msg, prefix, prefixlen, 0);
881dcaecb8bSclaudio 		break;
882dcaecb8bSclaudio 	case AID_VPN_IPv6:
8835ad4fcbaSclaudio 		r = nlri_get_vpn6(msg, prefix, prefixlen, 0);
884dcaecb8bSclaudio 		break;
885dcaecb8bSclaudio 	default:
886dcaecb8bSclaudio 		if (verbose)
887dcaecb8bSclaudio 			printf("unknown prefix AID %d\n", aid);
888dcaecb8bSclaudio 		return -1;
889dcaecb8bSclaudio 	}
890dcaecb8bSclaudio 	if (r == -1 && verbose)
891dcaecb8bSclaudio 		printf("failed to parse prefix of AID %d\n", aid);
892dcaecb8bSclaudio 	return r;
893dcaecb8bSclaudio }
894dcaecb8bSclaudio 
895*6b941460Sclaudio int
mrt_parse_state(struct mrt_bgp_state * s,struct mrt_hdr * hdr,struct ibuf * msg,int verbose)896*6b941460Sclaudio mrt_parse_state(struct mrt_bgp_state *s, struct mrt_hdr *hdr, struct ibuf *msg,
897*6b941460Sclaudio     int verbose)
898e86c4bdeSclaudio {
89985411ad9Sclaudio 	struct timespec		 t;
90059154960Sclaudio 	uint32_t		 sas, das, usec;
901*6b941460Sclaudio 	uint16_t		 sas16, das16, afi;
90259154960Sclaudio 	uint8_t			 aid;
903e86c4bdeSclaudio 
90485411ad9Sclaudio 	t.tv_sec = ntohl(hdr->timestamp);
90585411ad9Sclaudio 	t.tv_nsec = 0;
90685411ad9Sclaudio 
90785411ad9Sclaudio 	/* handle the microsec field for _ET header */
90885411ad9Sclaudio 	if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) {
909*6b941460Sclaudio 		if (ibuf_get_n32(msg, &usec) == -1)
910*6b941460Sclaudio 			return (-1);
911*6b941460Sclaudio 		t.tv_nsec = usec * 1000;
91285411ad9Sclaudio 	}
91385411ad9Sclaudio 
914e86c4bdeSclaudio 	switch (ntohs(hdr->subtype)) {
915e86c4bdeSclaudio 	case BGP4MP_STATE_CHANGE:
916*6b941460Sclaudio 		if (ibuf_get_n16(msg, &sas16) == -1 ||	/* source as */
917*6b941460Sclaudio 		    ibuf_get_n16(msg, &das16) == -1 ||	/* dest as */
918*6b941460Sclaudio 		    ibuf_skip(msg, 2) == -1 ||		/* if_index */
919*6b941460Sclaudio 		    ibuf_get_n16(msg, &afi) == -1)	/* afi */
920*6b941460Sclaudio 			return (-1);
921*6b941460Sclaudio 		sas = sas16;
922*6b941460Sclaudio 		das = das16;
923e86c4bdeSclaudio 		break;
924e86c4bdeSclaudio 	case BGP4MP_STATE_CHANGE_AS4:
925*6b941460Sclaudio 		if (ibuf_get_n32(msg, &sas) == -1 ||	/* source as */
926*6b941460Sclaudio 		    ibuf_get_n32(msg, &das) == -1 ||	/* dest as */
927*6b941460Sclaudio 		    ibuf_skip(msg, 2) == -1 ||		/* if_index */
928*6b941460Sclaudio 		    ibuf_get_n16(msg, &afi) == -1)	/* afi */
929*6b941460Sclaudio 			return (-1);
930e86c4bdeSclaudio 		break;
931e86c4bdeSclaudio 	default:
932e86c4bdeSclaudio 		errx(1, "mrt_parse_state: bad subtype");
933e86c4bdeSclaudio 	}
934e86c4bdeSclaudio 
935e86c4bdeSclaudio 	/* src & dst addr */
936dcaecb8bSclaudio 	if ((aid = mrt_afi2aid(afi, -1, verbose)) == AID_UNSPEC)
937*6b941460Sclaudio 		return (-1);
938e86c4bdeSclaudio 
939*6b941460Sclaudio 	memset(s, 0, sizeof(*s));
94085411ad9Sclaudio 	s->time = t;
941e86c4bdeSclaudio 	s->src_as = sas;
942e86c4bdeSclaudio 	s->dst_as = das;
943e86c4bdeSclaudio 
944*6b941460Sclaudio 	if (mrt_extract_addr(msg, &s->src, aid) == -1)
945*6b941460Sclaudio 		return (-1);
946*6b941460Sclaudio 	if (mrt_extract_addr(msg, &s->dst, aid) == -1)
947*6b941460Sclaudio 		return (-1);
948e86c4bdeSclaudio 
949e86c4bdeSclaudio 	/* states */
950*6b941460Sclaudio 	if (ibuf_get_n16(msg, &s->old_state) == -1 ||
951*6b941460Sclaudio 	    ibuf_get_n16(msg, &s->new_state) == -1)
952*6b941460Sclaudio 		return (-1);
953e86c4bdeSclaudio 
954*6b941460Sclaudio 	return (0);
955e86c4bdeSclaudio }
956e86c4bdeSclaudio 
957*6b941460Sclaudio int
mrt_parse_msg(struct mrt_bgp_msg * m,struct mrt_hdr * hdr,struct ibuf * msg,int verbose)958*6b941460Sclaudio mrt_parse_msg(struct mrt_bgp_msg *m, struct mrt_hdr *hdr, struct ibuf *msg,
959*6b941460Sclaudio     int verbose)
960e86c4bdeSclaudio {
96185411ad9Sclaudio 	struct timespec		 t;
96259154960Sclaudio 	uint32_t		 sas, das, usec;
963*6b941460Sclaudio 	uint16_t		 sas16, das16, afi;
964*6b941460Sclaudio 	int			 addpath = 0;
96559154960Sclaudio 	uint8_t			 aid;
966e86c4bdeSclaudio 
96785411ad9Sclaudio 	t.tv_sec = ntohl(hdr->timestamp);
96885411ad9Sclaudio 	t.tv_nsec = 0;
96985411ad9Sclaudio 
97085411ad9Sclaudio 	/* handle the microsec field for _ET header */
97185411ad9Sclaudio 	if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) {
972*6b941460Sclaudio 		if (ibuf_get_n32(msg, &usec) == -1)
973*6b941460Sclaudio 			return (-1);
974*6b941460Sclaudio 		t.tv_nsec = usec * 1000;
97585411ad9Sclaudio 	}
97685411ad9Sclaudio 
977e86c4bdeSclaudio 	switch (ntohs(hdr->subtype)) {
9789e59dee7Sclaudio 	case BGP4MP_MESSAGE_ADDPATH:
9799e59dee7Sclaudio 	case BGP4MP_MESSAGE_LOCAL_ADDPATH:
9809e59dee7Sclaudio 		addpath = 1;
9819e59dee7Sclaudio 		/* FALLTHROUGH */
982e86c4bdeSclaudio 	case BGP4MP_MESSAGE:
9839e59dee7Sclaudio 	case BGP4MP_MESSAGE_LOCAL:
984*6b941460Sclaudio 		if (ibuf_get_n16(msg, &sas16) == -1 ||	/* source as */
985*6b941460Sclaudio 		    ibuf_get_n16(msg, &das16) == -1 ||	/* dest as */
986*6b941460Sclaudio 		    ibuf_skip(msg, 2) == -1 ||		/* if_index */
987*6b941460Sclaudio 		    ibuf_get_n16(msg, &afi) == -1)	/* afi */
988*6b941460Sclaudio 			return (-1);
989*6b941460Sclaudio 		sas = sas16;
990*6b941460Sclaudio 		das = das16;
991e86c4bdeSclaudio 		break;
9929e59dee7Sclaudio 	case BGP4MP_MESSAGE_AS4_ADDPATH:
9939e59dee7Sclaudio 	case BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH:
9949e59dee7Sclaudio 		addpath = 1;
9959e59dee7Sclaudio 		/* FALLTHROUGH */
996e86c4bdeSclaudio 	case BGP4MP_MESSAGE_AS4:
9979e59dee7Sclaudio 	case BGP4MP_MESSAGE_AS4_LOCAL:
998*6b941460Sclaudio 		if (ibuf_get_n32(msg, &sas) == -1 ||	/* source as */
999*6b941460Sclaudio 		    ibuf_get_n32(msg, &das) == -1 ||	/* dest as */
1000*6b941460Sclaudio 		    ibuf_skip(msg, 2) == -1 ||		/* if_index */
1001*6b941460Sclaudio 		    ibuf_get_n16(msg, &afi) == -1)	/* afi */
1002*6b941460Sclaudio 			return (-1);
1003e86c4bdeSclaudio 		break;
1004e86c4bdeSclaudio 	default:
1005e86c4bdeSclaudio 		errx(1, "mrt_parse_msg: bad subtype");
1006e86c4bdeSclaudio 	}
1007e86c4bdeSclaudio 
1008e86c4bdeSclaudio 	/* src & dst addr */
1009dcaecb8bSclaudio 	if ((aid = mrt_afi2aid(afi, -1, verbose)) == AID_UNSPEC)
1010*6b941460Sclaudio 		return (-1);
1011e86c4bdeSclaudio 
1012*6b941460Sclaudio 	memset(m, 0, sizeof(*m));
101385411ad9Sclaudio 	m->time = t;
1014e86c4bdeSclaudio 	m->src_as = sas;
1015e86c4bdeSclaudio 	m->dst_as = das;
10169e59dee7Sclaudio 	m->add_path = addpath;
1017e86c4bdeSclaudio 
1018*6b941460Sclaudio 	if (mrt_extract_addr(msg, &m->src, aid) == -1 ||
1019*6b941460Sclaudio 	    mrt_extract_addr(msg, &m->dst, aid) == -1)
1020*6b941460Sclaudio 		return (-1);
1021e86c4bdeSclaudio 
1022e86c4bdeSclaudio 	/* msg */
1023*6b941460Sclaudio 	ibuf_from_ibuf(&m->msg, msg);
1024*6b941460Sclaudio 	return (0);
1025e86c4bdeSclaudio }
1026