xref: /openbsd-src/usr.sbin/bgpctl/mrtparser.c (revision 4e1ee0786f11cc571bd0be17d38e46f635c719fc)
1 /*	$OpenBSD: mrtparser.c,v 1.16 2021/09/22 18:17:49 claudio Exp $ */
2 /*
3  * Copyright (c) 2011 Claudio Jeker <claudio@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <err.h>
21 #include <errno.h>
22 #include <limits.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <time.h>
27 #include <unistd.h>
28 
29 #include "mrt.h"
30 #include "mrtparser.h"
31 
32 void	*mrt_read_msg(int, struct mrt_hdr *);
33 size_t	 mrt_read_buf(int, void *, size_t);
34 
35 struct mrt_peer	*mrt_parse_v2_peer(struct mrt_hdr *, void *);
36 struct mrt_rib	*mrt_parse_v2_rib(struct mrt_hdr *, void *, int);
37 int	mrt_parse_dump(struct mrt_hdr *, void *, struct mrt_peer **,
38 	    struct mrt_rib **);
39 int	mrt_parse_dump_mp(struct mrt_hdr *, void *, struct mrt_peer **,
40 	    struct mrt_rib **, int);
41 int	mrt_extract_attr(struct mrt_rib_entry *, u_char *, int, u_int8_t,
42 	    int);
43 
44 void	mrt_free_peers(struct mrt_peer *);
45 void	mrt_free_rib(struct mrt_rib *);
46 void	mrt_free_bgp_state(struct mrt_bgp_state *);
47 void	mrt_free_bgp_msg(struct mrt_bgp_msg *);
48 
49 u_char *mrt_aspath_inflate(void *, u_int16_t, u_int16_t *);
50 int	mrt_extract_addr(void *, u_int, struct bgpd_addr *, u_int8_t);
51 int	mrt_extract_prefix(void *, u_int, u_int8_t, struct bgpd_addr *,
52 	    u_int8_t *, int);
53 
54 struct mrt_bgp_state	*mrt_parse_state(struct mrt_hdr *, void *, int);
55 struct mrt_bgp_msg	*mrt_parse_msg(struct mrt_hdr *, void *, int);
56 
57 void *
58 mrt_read_msg(int fd, struct mrt_hdr *hdr)
59 {
60 	void *buf;
61 
62 	bzero(hdr, sizeof(*hdr));
63 	if (mrt_read_buf(fd, hdr, sizeof(*hdr)) != sizeof(*hdr))
64 		return (NULL);
65 
66 	if ((buf = malloc(ntohl(hdr->length))) == NULL)
67 		err(1, "malloc(%d)", hdr->length);
68 
69 	if (mrt_read_buf(fd, buf, ntohl(hdr->length)) != ntohl(hdr->length)) {
70 		free(buf);
71 		return (NULL);
72 	}
73 	return (buf);
74 }
75 
76 size_t
77 mrt_read_buf(int fd, void *buf, size_t len)
78 {
79 	char *b = buf;
80 	ssize_t n;
81 
82 	while (len > 0) {
83 		if ((n = read(fd, b, len)) == -1) {
84 			if (errno == EINTR)
85 				continue;
86 			err(1, "read");
87 		}
88 		if (n == 0)
89 			break;
90 		b += n;
91 		len -= n;
92 	}
93 
94 	return (b - (char *)buf);
95 }
96 
97 void
98 mrt_parse(int fd, struct mrt_parser *p, int verbose)
99 {
100 	struct mrt_hdr		h;
101 	struct mrt_peer		*pctx = NULL;
102 	struct mrt_rib		*r;
103 	struct mrt_bgp_state	*s;
104 	struct mrt_bgp_msg	*m;
105 	void			*msg;
106 
107 	while ((msg = mrt_read_msg(fd, &h))) {
108 		switch (ntohs(h.type)) {
109 		case MSG_NULL:
110 		case MSG_START:
111 		case MSG_DIE:
112 		case MSG_I_AM_DEAD:
113 		case MSG_PEER_DOWN:
114 		case MSG_PROTOCOL_BGP:
115 		case MSG_PROTOCOL_IDRP:
116 		case MSG_PROTOCOL_BGP4PLUS:
117 		case MSG_PROTOCOL_BGP4PLUS1:
118 			if (verbose)
119 				printf("deprecated MRT type %d\n",
120 				    ntohs(h.type));
121 			break;
122 		case MSG_PROTOCOL_RIP:
123 		case MSG_PROTOCOL_RIPNG:
124 		case MSG_PROTOCOL_OSPF:
125 		case MSG_PROTOCOL_ISIS_ET:
126 		case MSG_PROTOCOL_ISIS:
127 		case MSG_PROTOCOL_OSPFV3_ET:
128 		case MSG_PROTOCOL_OSPFV3:
129 			if (verbose)
130 				printf("unsuported MRT type %d\n",
131 				    ntohs(h.type));
132 			break;
133 		case MSG_TABLE_DUMP:
134 			switch (ntohs(h.subtype)) {
135 			case MRT_DUMP_AFI_IP:
136 			case MRT_DUMP_AFI_IPv6:
137 				if (p->dump == NULL)
138 					break;
139 				if (mrt_parse_dump(&h, msg, &pctx, &r) == 0) {
140 					if (p->dump)
141 						p->dump(r, pctx, p->arg);
142 					mrt_free_rib(r);
143 				}
144 				break;
145 			default:
146 				if (verbose)
147 					printf("unknown AFI %d in table dump\n",
148 					    ntohs(h.subtype));
149 				break;
150 			}
151 			break;
152 		case MSG_TABLE_DUMP_V2:
153 			switch (ntohs(h.subtype)) {
154 			case MRT_DUMP_V2_PEER_INDEX_TABLE:
155 				if (p->dump == NULL)
156 					break;
157 				if (pctx)
158 					mrt_free_peers(pctx);
159 				pctx = mrt_parse_v2_peer(&h, msg);
160 				break;
161 			case MRT_DUMP_V2_RIB_IPV4_UNICAST:
162 			case MRT_DUMP_V2_RIB_IPV4_MULTICAST:
163 			case MRT_DUMP_V2_RIB_IPV6_UNICAST:
164 			case MRT_DUMP_V2_RIB_IPV6_MULTICAST:
165 			case MRT_DUMP_V2_RIB_GENERIC:
166 			case MRT_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH:
167 			case MRT_DUMP_V2_RIB_IPV4_MULTICAST_ADDPATH:
168 			case MRT_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH:
169 			case MRT_DUMP_V2_RIB_IPV6_MULTICAST_ADDPATH:
170 			case MRT_DUMP_V2_RIB_GENERIC_ADDPATH:
171 				if (p->dump == NULL)
172 					break;
173 				r = mrt_parse_v2_rib(&h, msg, verbose);
174 				if (r) {
175 					if (p->dump)
176 						p->dump(r, pctx, p->arg);
177 					mrt_free_rib(r);
178 				}
179 				break;
180 			default:
181 				if (verbose)
182 					printf("unhandled DUMP_V2 subtype %d\n",
183 					    ntohs(h.subtype));
184 				break;
185 			}
186 			break;
187 		case MSG_PROTOCOL_BGP4MP_ET:
188 		case MSG_PROTOCOL_BGP4MP:
189 			switch (ntohs(h.subtype)) {
190 			case BGP4MP_STATE_CHANGE:
191 			case BGP4MP_STATE_CHANGE_AS4:
192 				if ((s = mrt_parse_state(&h, msg, verbose))) {
193 					if (p->state)
194 						p->state(s, p->arg);
195 					free(s);
196 				}
197 				break;
198 			case BGP4MP_MESSAGE:
199 			case BGP4MP_MESSAGE_AS4:
200 			case BGP4MP_MESSAGE_LOCAL:
201 			case BGP4MP_MESSAGE_AS4_LOCAL:
202 			case BGP4MP_MESSAGE_ADDPATH:
203 			case BGP4MP_MESSAGE_AS4_ADDPATH:
204 			case BGP4MP_MESSAGE_LOCAL_ADDPATH:
205 			case BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH:
206 				if ((m = mrt_parse_msg(&h, msg, verbose))) {
207 					if (p->message)
208 						p->message(m, p->arg);
209 					free(m->msg);
210 					free(m);
211 				}
212 				break;
213 			case BGP4MP_ENTRY:
214 				if (p->dump == NULL)
215 					break;
216 				if (mrt_parse_dump_mp(&h, msg, &pctx, &r,
217 				    verbose) == 0) {
218 					if (p->dump)
219 						p->dump(r, pctx, p->arg);
220 					mrt_free_rib(r);
221 				}
222 				break;
223 			default:
224 				if (verbose)
225 					printf("unhandled BGP4MP subtype %d\n",
226 					    ntohs(h.subtype));
227 				break;
228 			}
229 			break;
230 		default:
231 			if (verbose)
232 				printf("unknown MRT type %d\n", ntohs(h.type));
233 			break;
234 		}
235 		free(msg);
236 	}
237 	if (pctx)
238 		mrt_free_peers(pctx);
239 }
240 
241 static int
242 mrt_afi2aid(int afi, int safi, int verbose)
243 {
244 	switch (afi) {
245 	case MRT_DUMP_AFI_IP:
246 		if (safi == -1 || safi == 1 || safi == 2)
247 			return AID_INET;
248 		else if (safi == 128)
249 			return AID_VPN_IPv4;
250 		break;
251 	case MRT_DUMP_AFI_IPv6:
252 		if (safi == -1 || safi == 1 || safi == 2)
253 			return AID_INET6;
254 		else if (safi == 128)
255 			return AID_VPN_IPv6;
256 		break;
257 	default:
258 		break;
259 	}
260 	if (verbose)
261 		printf("unhandled AFI/SAFI %d/%d\n", afi, safi);
262 	return AID_UNSPEC;
263 }
264 
265 struct mrt_peer *
266 mrt_parse_v2_peer(struct mrt_hdr *hdr, void *msg)
267 {
268 	struct mrt_peer_entry	*peers = NULL;
269 	struct mrt_peer	*p;
270 	u_int8_t	*b = msg;
271 	u_int32_t	bid, as4;
272 	u_int16_t	cnt, i, as2;
273 	u_int		len = ntohl(hdr->length);
274 
275 	if (len < 8)	/* min msg size */
276 		return NULL;
277 
278 	p = calloc(1, sizeof(struct mrt_peer));
279 	if (p == NULL)
280 		err(1, "calloc");
281 
282 	/* collector bgp id */
283 	memcpy(&bid, b, sizeof(bid));
284 	b += sizeof(bid);
285 	len -= sizeof(bid);
286 	p->bgp_id = ntohl(bid);
287 
288 	/* view name length */
289 	memcpy(&cnt, b, sizeof(cnt));
290 	b += sizeof(cnt);
291 	len -= sizeof(cnt);
292 	cnt = ntohs(cnt);
293 
294 	/* view name */
295 	if (cnt > len)
296 		goto fail;
297 	if (cnt != 0) {
298 		if ((p->view = malloc(cnt + 1)) == NULL)
299 			err(1, "malloc");
300 		memcpy(p->view, b, cnt);
301 		p->view[cnt] = 0;
302 	} else
303 		if ((p->view = strdup("")) == NULL)
304 			err(1, "strdup");
305 	b += cnt;
306 	len -= cnt;
307 
308 	/* peer_count */
309 	if (len < sizeof(cnt))
310 		goto fail;
311 	memcpy(&cnt, b, sizeof(cnt));
312 	b += sizeof(cnt);
313 	len -= sizeof(cnt);
314 	cnt = ntohs(cnt);
315 
316 	/* peer entries */
317 	if ((peers = calloc(cnt, sizeof(struct mrt_peer_entry))) == NULL)
318 		err(1, "calloc");
319 	for (i = 0; i < cnt; i++) {
320 		u_int8_t type;
321 
322 		if (len < sizeof(u_int8_t) + sizeof(u_int32_t))
323 			goto fail;
324 		type = *b++;
325 		len -= 1;
326 		memcpy(&bid, b, sizeof(bid));
327 		b += sizeof(bid);
328 		len -= sizeof(bid);
329 		peers[i].bgp_id = ntohl(bid);
330 
331 		if (type & MRT_DUMP_V2_PEER_BIT_I) {
332 			if (mrt_extract_addr(b, len, &peers[i].addr,
333 			    AID_INET6) == -1)
334 				goto fail;
335 			b += sizeof(struct in6_addr);
336 			len -= sizeof(struct in6_addr);
337 		} else {
338 			if (mrt_extract_addr(b, len, &peers[i].addr,
339 			    AID_INET) == -1)
340 				goto fail;
341 			b += sizeof(struct in_addr);
342 			len -= sizeof(struct in_addr);
343 		}
344 
345 		if (type & MRT_DUMP_V2_PEER_BIT_A) {
346 			memcpy(&as4, b, sizeof(as4));
347 			b += sizeof(as4);
348 			len -= sizeof(as4);
349 			as4 = ntohl(as4);
350 		} else {
351 			memcpy(&as2, b, sizeof(as2));
352 			b += sizeof(as2);
353 			len -= sizeof(as2);
354 			as4 = ntohs(as2);
355 		}
356 		peers[i].asnum = as4;
357 	}
358 	p->peers = peers;
359 	p->npeers = cnt;
360 	return (p);
361 fail:
362 	mrt_free_peers(p);
363 	free(peers);
364 	return (NULL);
365 }
366 
367 struct mrt_rib *
368 mrt_parse_v2_rib(struct mrt_hdr *hdr, void *msg, int verbose)
369 {
370 	struct mrt_rib_entry *entries = NULL;
371 	struct mrt_rib	*r;
372 	u_int8_t	*b = msg;
373 	u_int		len = ntohl(hdr->length);
374 	u_int32_t	snum, path_id = 0;
375 	u_int16_t	cnt, i, afi;
376 	u_int8_t	safi, aid;
377 	int		ret;
378 
379 	if (len < sizeof(snum) + 1)
380 		return NULL;
381 
382 	r = calloc(1, sizeof(struct mrt_rib));
383 	if (r == NULL)
384 		err(1, "calloc");
385 
386 	/* seq_num */
387 	memcpy(&snum, b, sizeof(snum));
388 	b += sizeof(snum);
389 	len -= sizeof(snum);
390 	r->seqnum = ntohl(snum);
391 
392 	switch (ntohs(hdr->subtype)) {
393 	case MRT_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH:
394 	case MRT_DUMP_V2_RIB_IPV4_MULTICAST_ADDPATH:
395 		r->add_path = 1;
396 		/* FALLTHROUGH */
397 	case MRT_DUMP_V2_RIB_IPV4_UNICAST:
398 	case MRT_DUMP_V2_RIB_IPV4_MULTICAST:
399 		/* prefix */
400 		ret = mrt_extract_prefix(b, len, AID_INET, &r->prefix,
401 		    &r->prefixlen, verbose);
402 		if (ret == 1)
403 			goto fail;
404 		break;
405 	case MRT_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH:
406 	case MRT_DUMP_V2_RIB_IPV6_MULTICAST_ADDPATH:
407 		r->add_path = 1;
408 		/* FALLTHROUGH */
409 	case MRT_DUMP_V2_RIB_IPV6_UNICAST:
410 	case MRT_DUMP_V2_RIB_IPV6_MULTICAST:
411 		/* prefix */
412 		ret = mrt_extract_prefix(b, len, AID_INET6, &r->prefix,
413 		    &r->prefixlen, verbose);
414 		if (ret == 1)
415 			goto fail;
416 		break;
417 	case MRT_DUMP_V2_RIB_GENERIC_ADDPATH:
418 		/*
419 		 * RFC8050 handling for add-path has special handling for
420 		 * RIB_GENERIC_ADDPATH but nobody implements it that way.
421 		 * So just use the same way as for the other _ADDPATH types.
422 		 */
423 		r->add_path = 1;
424 		/* FALLTHROUGH */
425 	case MRT_DUMP_V2_RIB_GENERIC:
426 		/* fetch AFI/SAFI pair */
427 		if (len < 3)
428 			goto fail;
429 		memcpy(&afi, b, sizeof(afi));
430 		b += sizeof(afi);
431 		len -= sizeof(afi);
432 		afi = ntohs(afi);
433 
434 		safi = *b++;
435 		len -= 1;
436 
437 		if ((aid = mrt_afi2aid(afi, safi, verbose)) == AID_UNSPEC)
438 			goto fail;
439 
440 		/* prefix */
441 		ret = mrt_extract_prefix(b, len, aid, &r->prefix,
442 		    &r->prefixlen, verbose);
443 		if (ret == 1)
444 			goto fail;
445 		break;
446 	default:
447 		errx(1, "unknonw subtype %hd", ntohs(hdr->subtype));
448 	}
449 
450 	/* adjust length */
451 	b += ret;
452 	len -= ret;
453 
454 	/* entries count */
455 	if (len < sizeof(cnt))
456 		goto fail;
457 	memcpy(&cnt, b, sizeof(cnt));
458 	b += sizeof(cnt);
459 	len -= sizeof(cnt);
460 	cnt = ntohs(cnt);
461 	r->nentries = cnt;
462 
463 	/* entries */
464 	if ((entries = calloc(cnt, sizeof(struct mrt_rib_entry))) == NULL)
465 		err(1, "calloc");
466 	for (i = 0; i < cnt; i++) {
467 		u_int32_t	otm;
468 		u_int16_t	pix, alen;
469 		if (len < 2 * sizeof(u_int16_t) + sizeof(u_int32_t))
470 			goto fail;
471 		/* peer index */
472 		memcpy(&pix, b, sizeof(pix));
473 		b += sizeof(pix);
474 		len -= sizeof(pix);
475 		entries[i].peer_idx = ntohs(pix);
476 
477 		/* originated */
478 		memcpy(&otm, b, sizeof(otm));
479 		b += sizeof(otm);
480 		len -= sizeof(otm);
481 		entries[i].originated = ntohl(otm);
482 
483 		if (r->add_path) {
484 			if (len < sizeof(path_id) + sizeof(alen))
485 				goto fail;
486 			memcpy(&path_id, b, sizeof(path_id));
487 			b += sizeof(path_id);
488 			len -= sizeof(path_id);
489 			path_id = ntohl(path_id);
490 		}
491 		entries[i].path_id = path_id;
492 
493 		/* attr_len */
494 		memcpy(&alen, b, sizeof(alen));
495 		b += sizeof(alen);
496 		len -= sizeof(alen);
497 		alen = ntohs(alen);
498 
499 		/* attr */
500 		if (len < alen)
501 			goto fail;
502 		if (mrt_extract_attr(&entries[i], b, alen,
503 		    r->prefix.aid, 1) == -1)
504 			goto fail;
505 		b += alen;
506 		len -= alen;
507 	}
508 	r->entries = entries;
509 	return (r);
510 fail:
511 	mrt_free_rib(r);
512 	free(entries);
513 	return (NULL);
514 }
515 
516 int
517 mrt_parse_dump(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp,
518     struct mrt_rib **rp)
519 {
520 	struct mrt_peer		*p;
521 	struct mrt_rib		*r;
522 	struct mrt_rib_entry	*re;
523 	u_int8_t		*b = msg;
524 	u_int			 len = ntohl(hdr->length);
525 	u_int16_t		 asnum, alen;
526 
527 	if (*pp == NULL) {
528 		*pp = calloc(1, sizeof(struct mrt_peer));
529 		if (*pp == NULL)
530 			err(1, "calloc");
531 		(*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry));
532 		if ((*pp)->peers == NULL)
533 			err(1, "calloc");
534 		(*pp)->npeers = 1;
535 	}
536 	p = *pp;
537 
538 	*rp = r = calloc(1, sizeof(struct mrt_rib));
539 	if (r == NULL)
540 		err(1, "calloc");
541 	re = calloc(1, sizeof(struct mrt_rib_entry));
542 	if (re == NULL)
543 		err(1, "calloc");
544 	r->nentries = 1;
545 	r->entries = re;
546 
547 	if (len < 2 * sizeof(u_int16_t))
548 		goto fail;
549 	/* view */
550 	b += sizeof(u_int16_t);
551 	len -= sizeof(u_int16_t);
552 	/* seqnum */
553 	memcpy(&r->seqnum, b, sizeof(u_int16_t));
554 	b += sizeof(u_int16_t);
555 	len -= sizeof(u_int16_t);
556 	r->seqnum = ntohs(r->seqnum);
557 
558 	switch (ntohs(hdr->subtype)) {
559 	case MRT_DUMP_AFI_IP:
560 		if (mrt_extract_addr(b, len, &r->prefix, AID_INET) == -1)
561 			goto fail;
562 		b += sizeof(struct in_addr);
563 		len -= sizeof(struct in_addr);
564 		break;
565 	case MRT_DUMP_AFI_IPv6:
566 		if (mrt_extract_addr(b, len, &r->prefix, AID_INET6) == -1)
567 			goto fail;
568 		b += sizeof(struct in6_addr);
569 		len -= sizeof(struct in6_addr);
570 		break;
571 	}
572 	if (len < 2 * sizeof(u_int32_t) + 2 * sizeof(u_int16_t) + 2)
573 		goto fail;
574 	r->prefixlen = *b++;
575 	len -= 1;
576 	/* status */
577 	b += 1;
578 	len -= 1;
579 	/* originated */
580 	memcpy(&re->originated, b, sizeof(u_int32_t));
581 	b += sizeof(u_int32_t);
582 	len -= sizeof(u_int32_t);
583 	re->originated = ntohl(re->originated);
584 	/* peer ip */
585 	switch (ntohs(hdr->subtype)) {
586 	case MRT_DUMP_AFI_IP:
587 		if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET) == -1)
588 			goto fail;
589 		b += sizeof(struct in_addr);
590 		len -= sizeof(struct in_addr);
591 		break;
592 	case MRT_DUMP_AFI_IPv6:
593 		if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET6) == -1)
594 			goto fail;
595 		b += sizeof(struct in6_addr);
596 		len -= sizeof(struct in6_addr);
597 		break;
598 	}
599 	memcpy(&asnum, b, sizeof(asnum));
600 	b += sizeof(asnum);
601 	len -= sizeof(asnum);
602 	p->peers->asnum = ntohs(asnum);
603 
604 	memcpy(&alen, b, sizeof(alen));
605 	b += sizeof(alen);
606 	len -= sizeof(alen);
607 	alen = ntohs(alen);
608 
609 	/* attr */
610 	if (len < alen)
611 		goto fail;
612 	if (mrt_extract_attr(re, b, alen, r->prefix.aid, 0) == -1)
613 		goto fail;
614 	b += alen;
615 	len -= alen;
616 
617 	return (0);
618 fail:
619 	mrt_free_rib(r);
620 	return (-1);
621 }
622 
623 int
624 mrt_parse_dump_mp(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp,
625     struct mrt_rib **rp, int verbose)
626 {
627 	struct mrt_peer		*p;
628 	struct mrt_rib		*r;
629 	struct mrt_rib_entry	*re;
630 	u_int8_t		*b = msg;
631 	u_int			 len = ntohl(hdr->length);
632 	u_int16_t		 asnum, alen, afi;
633 	u_int8_t		 safi, nhlen, aid;
634 	int			 ret;
635 
636 	/* just ignore the microsec field for _ET header for now */
637 	if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) {
638 		b = (char *)b + sizeof(u_int32_t);
639 		len -= sizeof(u_int32_t);
640 	}
641 
642 	if (*pp == NULL) {
643 		*pp = calloc(1, sizeof(struct mrt_peer));
644 		if (*pp == NULL)
645 			err(1, "calloc");
646 		(*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry));
647 		if ((*pp)->peers == NULL)
648 			err(1, "calloc");
649 		(*pp)->npeers = 1;
650 	}
651 	p = *pp;
652 
653 	*rp = r = calloc(1, sizeof(struct mrt_rib));
654 	if (r == NULL)
655 		err(1, "calloc");
656 	re = calloc(1, sizeof(struct mrt_rib_entry));
657 	if (re == NULL)
658 		err(1, "calloc");
659 	r->nentries = 1;
660 	r->entries = re;
661 
662 	if (len < 4 * sizeof(u_int16_t))
663 		goto fail;
664 	/* source AS */
665 	b += sizeof(u_int16_t);
666 	len -= sizeof(u_int16_t);
667 	/* dest AS */
668 	memcpy(&asnum, b, sizeof(asnum));
669 	b += sizeof(asnum);
670 	len -= sizeof(asnum);
671 	p->peers->asnum = ntohs(asnum);
672 	/* iface index */
673 	b += sizeof(u_int16_t);
674 	len -= sizeof(u_int16_t);
675 	/* afi */
676 	memcpy(&afi, b, sizeof(afi));
677 	b += sizeof(afi);
678 	len -= sizeof(afi);
679 	afi = ntohs(afi);
680 
681 	/* source + dest ip */
682 	switch (afi) {
683 	case MRT_DUMP_AFI_IP:
684 		if (len < 2 * sizeof(struct in_addr))
685 			goto fail;
686 		/* source IP */
687 		b += sizeof(struct in_addr);
688 		len -= sizeof(struct in_addr);
689 		/* dest IP */
690 		if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET) == -1)
691 			goto fail;
692 		b += sizeof(struct in_addr);
693 		len -= sizeof(struct in_addr);
694 		break;
695 	case MRT_DUMP_AFI_IPv6:
696 		if (len < 2 * sizeof(struct in6_addr))
697 			goto fail;
698 		/* source IP */
699 		b += sizeof(struct in6_addr);
700 		len -= sizeof(struct in6_addr);
701 		/* dest IP */
702 		if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET6) == -1)
703 			goto fail;
704 		b += sizeof(struct in6_addr);
705 		len -= sizeof(struct in6_addr);
706 		break;
707 	}
708 
709 	if (len < 2 * sizeof(u_int16_t) + 2 * sizeof(u_int32_t))
710 		goto fail;
711 	/* view + status */
712 	b += 2 * sizeof(u_int16_t);
713 	len -= 2 * sizeof(u_int16_t);
714 	/* originated */
715 	memcpy(&re->originated, b, sizeof(u_int32_t));
716 	b += sizeof(u_int32_t);
717 	len -= sizeof(u_int32_t);
718 	re->originated = ntohl(re->originated);
719 
720 	/* afi */
721 	memcpy(&afi, b, sizeof(afi));
722 	b += sizeof(afi);
723 	len -= sizeof(afi);
724 	afi = ntohs(afi);
725 
726 	/* safi */
727 	safi = *b++;
728 	len -= 1;
729 
730 	if ((aid = mrt_afi2aid(afi, safi, verbose)) == AID_UNSPEC)
731 		goto fail;
732 
733 	/* nhlen */
734 	nhlen = *b++;
735 	len -= 1;
736 
737 	/* nexthop */
738 	if (mrt_extract_addr(b, len, &re->nexthop, aid) == -1)
739 		goto fail;
740 	if (len < nhlen)
741 		goto fail;
742 	b += nhlen;
743 	len -= nhlen;
744 
745 	/* prefix */
746 	ret = mrt_extract_prefix(b, len, aid, &r->prefix, &r->prefixlen,
747 	    verbose);
748 	if (ret == 1)
749 		goto fail;
750 	b += ret;
751 	len -= ret;
752 
753 	memcpy(&alen, b, sizeof(alen));
754 	b += sizeof(alen);
755 	len -= sizeof(alen);
756 	alen = ntohs(alen);
757 
758 	/* attr */
759 	if (len < alen)
760 		goto fail;
761 	if (mrt_extract_attr(re, b, alen, r->prefix.aid, 0) == -1)
762 		goto fail;
763 	b += alen;
764 	len -= alen;
765 
766 	return (0);
767 fail:
768 	mrt_free_rib(r);
769 	return (-1);
770 }
771 
772 int
773 mrt_extract_attr(struct mrt_rib_entry *re, u_char *a, int alen, u_int8_t aid,
774     int as4)
775 {
776 	struct mrt_attr	*ap;
777 	u_int32_t	tmp;
778 	u_int16_t	attr_len;
779 	u_int8_t	type, flags, *attr;
780 
781 	do {
782 		if (alen < 3)
783 			return (-1);
784 		attr = a;
785 		flags = *a++;
786 		alen -= 1;
787 		type = *a++;
788 		alen -= 1;
789 
790 		if (flags & MRT_ATTR_EXTLEN) {
791 			if (alen < 2)
792 				return (-1);
793 			memcpy(&attr_len, a, sizeof(attr_len));
794 			attr_len = ntohs(attr_len);
795 			a += sizeof(attr_len);
796 			alen -= sizeof(attr_len);
797 		} else {
798 			attr_len = *a++;
799 			alen -= 1;
800 		}
801 		switch (type) {
802 		case MRT_ATTR_ORIGIN:
803 			if (attr_len != 1)
804 				return (-1);
805 			re->origin = *a;
806 			break;
807 		case MRT_ATTR_ASPATH:
808 			if (as4) {
809 				re->aspath_len = attr_len;
810 				if ((re->aspath = malloc(attr_len)) == NULL)
811 					err(1, "malloc");
812 				memcpy(re->aspath, a, attr_len);
813 			} else {
814 				re->aspath = mrt_aspath_inflate(a, attr_len,
815 				    &re->aspath_len);
816 				if (re->aspath == NULL)
817 					return (-1);
818 			}
819 			break;
820 		case MRT_ATTR_NEXTHOP:
821 			if (attr_len != 4)
822 				return (-1);
823 			if (aid != AID_INET)
824 				break;
825 			memcpy(&tmp, a, sizeof(tmp));
826 			re->nexthop.aid = AID_INET;
827 			re->nexthop.v4.s_addr = tmp;
828 			break;
829 		case MRT_ATTR_MED:
830 			if (attr_len != 4)
831 				return (-1);
832 			memcpy(&tmp, a, sizeof(tmp));
833 			re->med = ntohl(tmp);
834 			break;
835 		case MRT_ATTR_LOCALPREF:
836 			if (attr_len != 4)
837 				return (-1);
838 			memcpy(&tmp, a, sizeof(tmp));
839 			re->local_pref = ntohl(tmp);
840 			break;
841 		case MRT_ATTR_MP_REACH_NLRI:
842 			/*
843 			 * XXX horrible hack:
844 			 * Once again IETF and the real world differ in the
845 			 * implementation. In short the abbreviated MP_NLRI
846 			 * hack in the standard is not used in real life.
847 			 * Detect the two cases by looking at the first byte
848 			 * of the payload (either the nexthop addr length (RFC)
849 			 * or the high byte of the AFI (old form)). If the
850 			 * first byte matches the expected nexthop length it
851 			 * is expected to be the RFC 6396 encoding.
852 			 */
853 			if (*a != attr_len - 1) {
854 				a += 3;
855 				alen -= 3;
856 				attr_len -= 3;
857 			}
858 			switch (aid) {
859 			case AID_INET6:
860 				if (attr_len < sizeof(struct in6_addr) + 1)
861 					return (-1);
862 				re->nexthop.aid = aid;
863 				memcpy(&re->nexthop.v6, a + 1,
864 				    sizeof(struct in6_addr));
865 				break;
866 			case AID_VPN_IPv4:
867 				if (attr_len < sizeof(u_int64_t) +
868 				    sizeof(struct in_addr))
869 					return (-1);
870 				re->nexthop.aid = aid;
871 				memcpy(&tmp, a + 1 + sizeof(u_int64_t),
872 				    sizeof(tmp));
873 				re->nexthop.v4.s_addr = tmp;
874 				break;
875 			case AID_VPN_IPv6:
876 				if (attr_len < sizeof(u_int64_t) +
877 				    sizeof(struct in6_addr))
878 					return (-1);
879 				re->nexthop.aid = aid;
880 				memcpy(&re->nexthop.v6,
881 				    a + 1 + sizeof(u_int64_t),
882 				    sizeof(struct in6_addr));
883 				break;
884 			}
885 			break;
886 		case MRT_ATTR_AS4PATH:
887 			if (!as4) {
888 				free(re->aspath);
889 				re->aspath_len = attr_len;
890 				if ((re->aspath = malloc(attr_len)) == NULL)
891 					err(1, "malloc");
892 				memcpy(re->aspath, a, attr_len);
893 				break;
894 			}
895 			/* FALLTHROUGH */
896 		default:
897 			re->nattrs++;
898 			if (re->nattrs >= UCHAR_MAX)
899 				err(1, "too many attributes");
900 			ap = reallocarray(re->attrs,
901 			    re->nattrs, sizeof(struct mrt_attr));
902 			if (ap == NULL)
903 				err(1, "realloc");
904 			re->attrs = ap;
905 			ap = re->attrs + re->nattrs - 1;
906 			ap->attr_len = a + attr_len - attr;
907 			if ((ap->attr = malloc(ap->attr_len)) == NULL)
908 				err(1, "malloc");
909 			memcpy(ap->attr, attr, ap->attr_len);
910 			break;
911 		}
912 		a += attr_len;
913 		alen -= attr_len;
914 	} while (alen > 0);
915 
916 	return (0);
917 }
918 
919 void
920 mrt_free_peers(struct mrt_peer *p)
921 {
922 	free(p->peers);
923 	free(p->view);
924 	free(p);
925 }
926 
927 void
928 mrt_free_rib(struct mrt_rib *r)
929 {
930 	u_int16_t	i, j;
931 
932 	for (i = 0; i < r->nentries && r->entries; i++) {
933 		for (j = 0; j < r->entries[i].nattrs; j++)
934 			 free(r->entries[i].attrs[j].attr);
935 		free(r->entries[i].attrs);
936 		free(r->entries[i].aspath);
937 	}
938 
939 	free(r->entries);
940 	free(r);
941 }
942 
943 void
944 mrt_free_bgp_state(struct mrt_bgp_state *s)
945 {
946 	free(s);
947 }
948 
949 void
950 mrt_free_bgp_msg(struct mrt_bgp_msg *m)
951 {
952 	free(m->msg);
953 	free(m);
954 }
955 
956 u_char *
957 mrt_aspath_inflate(void *data, u_int16_t len, u_int16_t *newlen)
958 {
959 	u_int8_t	*seg, *nseg, *ndata;
960 	u_int16_t	 seg_size, olen, nlen;
961 	u_int8_t	 seg_len;
962 
963 	/* first calculate the length of the aspath */
964 	seg = data;
965 	nlen = 0;
966 	for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) {
967 		seg_len = seg[1];
968 		seg_size = 2 + sizeof(u_int16_t) * seg_len;
969 		nlen += 2 + sizeof(u_int32_t) * seg_len;
970 
971 		if (seg_size > olen)
972 			return NULL;
973 	}
974 
975 	*newlen = nlen;
976 	if ((ndata = malloc(nlen)) == NULL)
977 		err(1, "malloc");
978 
979 	/* then copy the aspath */
980 	seg = data;
981 	for (nseg = ndata; nseg < ndata + nlen; ) {
982 		*nseg++ = *seg++;
983 		*nseg++ = seg_len = *seg++;
984 		for (; seg_len > 0; seg_len--) {
985 			*nseg++ = 0;
986 			*nseg++ = 0;
987 			*nseg++ = *seg++;
988 			*nseg++ = *seg++;
989 		}
990 	}
991 
992 	return (ndata);
993 }
994 
995 int
996 mrt_extract_addr(void *msg, u_int len, struct bgpd_addr *addr, u_int8_t aid)
997 {
998 	u_int8_t	*b = msg;
999 
1000 	memset(addr, 0, sizeof(*addr));
1001 	switch (aid) {
1002 	case AID_INET:
1003 		if (len < sizeof(struct in_addr))
1004 			return (-1);
1005 		addr->aid = aid;
1006 		memcpy(&addr->v4, b, sizeof(struct in_addr));
1007 		return sizeof(struct in_addr);
1008 	case AID_INET6:
1009 		if (len < sizeof(struct in6_addr))
1010 			return (-1);
1011 		addr->aid = aid;
1012 		memcpy(&addr->v6, b, sizeof(struct in6_addr));
1013 		return sizeof(struct in6_addr);
1014 	case AID_VPN_IPv4:
1015 		if (len < sizeof(u_int64_t) + sizeof(struct in_addr))
1016 			return (-1);
1017 		addr->aid = aid;
1018 		/* XXX labelstack and rd missing */
1019 		memcpy(&addr->v4, b + sizeof(u_int64_t),
1020 		    sizeof(struct in_addr));
1021 		return (sizeof(u_int64_t) + sizeof(struct in_addr));
1022 	case AID_VPN_IPv6:
1023 		if (len < sizeof(u_int64_t) + sizeof(struct in6_addr))
1024 			return (-1);
1025 		addr->aid = aid;
1026 		/* XXX labelstack and rd missing */
1027 		memcpy(&addr->v6, b + sizeof(u_int64_t),
1028 		    sizeof(struct in6_addr));
1029 		return (sizeof(u_int64_t) + sizeof(struct in6_addr));
1030 	default:
1031 		return (-1);
1032 	}
1033 }
1034 
1035 int
1036 mrt_extract_prefix(void *msg, u_int len, u_int8_t aid,
1037     struct bgpd_addr *prefix, u_int8_t *prefixlen, int verbose)
1038 {
1039 	int r;
1040 
1041 	switch (aid) {
1042 	case AID_INET:
1043 		r = nlri_get_prefix(msg, len, prefix, prefixlen);
1044 		break;
1045 	case AID_INET6:
1046 		r = nlri_get_prefix6(msg, len, prefix, prefixlen);
1047 		break;
1048 	case AID_VPN_IPv4:
1049 		r = nlri_get_vpn4(msg, len, prefix, prefixlen, 0);
1050 		break;
1051 	case AID_VPN_IPv6:
1052 		r = nlri_get_vpn6(msg, len, prefix, prefixlen, 0);
1053 		break;
1054 	default:
1055 		if (verbose)
1056 			printf("unknown prefix AID %d\n", aid);
1057 		return -1;
1058 	}
1059 	if (r == -1 && verbose)
1060 		printf("failed to parse prefix of AID %d\n", aid);
1061 	return r;
1062 }
1063 
1064 struct mrt_bgp_state *
1065 mrt_parse_state(struct mrt_hdr *hdr, void *msg, int verbose)
1066 {
1067 	struct timespec		 t;
1068 	struct mrt_bgp_state	*s;
1069 	u_int8_t		*b = msg;
1070 	u_int			 len = ntohl(hdr->length);
1071 	u_int32_t		 sas, das, usec;
1072 	u_int16_t		 tmp16, afi;
1073 	int			 r;
1074 	u_int8_t		 aid;
1075 
1076 	t.tv_sec = ntohl(hdr->timestamp);
1077 	t.tv_nsec = 0;
1078 
1079 	/* handle the microsec field for _ET header */
1080 	if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) {
1081 		memcpy(&usec, b, sizeof(usec));
1082 		b += sizeof(usec);
1083 		len -= sizeof(usec);
1084 		t.tv_nsec = ntohl(usec) * 1000;
1085 	}
1086 
1087 	switch (ntohs(hdr->subtype)) {
1088 	case BGP4MP_STATE_CHANGE:
1089 		if (len < 8)
1090 			return (0);
1091 		/* source as */
1092 		memcpy(&tmp16, b, sizeof(tmp16));
1093 		b += sizeof(tmp16);
1094 		len -= sizeof(tmp16);
1095 		sas = ntohs(tmp16);
1096 		/* dest as */
1097 		memcpy(&tmp16, b, sizeof(tmp16));
1098 		b += sizeof(tmp16);
1099 		len -= sizeof(tmp16);
1100 		das = ntohs(tmp16);
1101 		/* if_index, ignored */
1102 		b += sizeof(tmp16);
1103 		len -= sizeof(tmp16);
1104 		/* afi */
1105 		memcpy(&tmp16, b, sizeof(tmp16));
1106 		b += sizeof(tmp16);
1107 		len -= sizeof(tmp16);
1108 		afi = ntohs(tmp16);
1109 		break;
1110 	case BGP4MP_STATE_CHANGE_AS4:
1111 		if (len < 12)
1112 			return (0);
1113 		/* source as */
1114 		memcpy(&sas, b, sizeof(sas));
1115 		b += sizeof(sas);
1116 		len -= sizeof(sas);
1117 		sas = ntohl(sas);
1118 		/* dest as */
1119 		memcpy(&das, b, sizeof(das));
1120 		b += sizeof(das);
1121 		len -= sizeof(das);
1122 		das = ntohl(das);
1123 		/* if_index, ignored */
1124 		b += sizeof(tmp16);
1125 		len -= sizeof(tmp16);
1126 		/* afi */
1127 		memcpy(&tmp16, b, sizeof(tmp16));
1128 		b += sizeof(tmp16);
1129 		len -= sizeof(tmp16);
1130 		afi = ntohs(tmp16);
1131 		break;
1132 	default:
1133 		errx(1, "mrt_parse_state: bad subtype");
1134 	}
1135 
1136 	/* src & dst addr */
1137 	if ((aid = mrt_afi2aid(afi, -1, verbose)) == AID_UNSPEC)
1138 		return (NULL);
1139 
1140 	if ((s = calloc(1, sizeof(struct mrt_bgp_state))) == NULL)
1141 		err(1, "calloc");
1142 	s->time = t;
1143 	s->src_as = sas;
1144 	s->dst_as = das;
1145 
1146 	if ((r = mrt_extract_addr(b, len, &s->src, aid)) == -1)
1147 		goto fail;
1148 	b += r;
1149 	len -= r;
1150 	if ((r = mrt_extract_addr(b, len, &s->dst, aid)) == -1)
1151 		goto fail;
1152 	b += r;
1153 	len -= r;
1154 
1155 	/* states */
1156 	memcpy(&tmp16, b, sizeof(tmp16));
1157 	b += sizeof(tmp16);
1158 	len -= sizeof(tmp16);
1159 	s->old_state = ntohs(tmp16);
1160 	memcpy(&tmp16, b, sizeof(tmp16));
1161 	b += sizeof(tmp16);
1162 	len -= sizeof(tmp16);
1163 	s->new_state = ntohs(tmp16);
1164 
1165 	return (s);
1166 
1167 fail:
1168 	free(s);
1169 	return (NULL);
1170 }
1171 
1172 struct mrt_bgp_msg *
1173 mrt_parse_msg(struct mrt_hdr *hdr, void *msg, int verbose)
1174 {
1175 	struct timespec		 t;
1176 	struct mrt_bgp_msg	*m;
1177 	u_int8_t		*b = msg;
1178 	u_int			 len = ntohl(hdr->length);
1179 	u_int32_t		 sas, das, usec;
1180 	u_int16_t		 tmp16, afi;
1181 	int			 r, addpath = 0;
1182 	u_int8_t		 aid;
1183 
1184 	t.tv_sec = ntohl(hdr->timestamp);
1185 	t.tv_nsec = 0;
1186 
1187 	/* handle the microsec field for _ET header */
1188 	if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) {
1189 		memcpy(&usec, b, sizeof(usec));
1190 		b += sizeof(usec);
1191 		len -= sizeof(usec);
1192 		t.tv_nsec = ntohl(usec) * 1000;
1193 	}
1194 
1195 	switch (ntohs(hdr->subtype)) {
1196 	case BGP4MP_MESSAGE_ADDPATH:
1197 	case BGP4MP_MESSAGE_LOCAL_ADDPATH:
1198 		addpath = 1;
1199 		/* FALLTHROUGH */
1200 	case BGP4MP_MESSAGE:
1201 	case BGP4MP_MESSAGE_LOCAL:
1202 		if (len < 8)
1203 			return (0);
1204 		/* source as */
1205 		memcpy(&tmp16, b, sizeof(tmp16));
1206 		b += sizeof(tmp16);
1207 		len -= sizeof(tmp16);
1208 		sas = ntohs(tmp16);
1209 		/* dest as */
1210 		memcpy(&tmp16, b, sizeof(tmp16));
1211 		b += sizeof(tmp16);
1212 		len -= sizeof(tmp16);
1213 		das = ntohs(tmp16);
1214 		/* if_index, ignored */
1215 		b += sizeof(tmp16);
1216 		len -= sizeof(tmp16);
1217 		/* afi */
1218 		memcpy(&tmp16, b, sizeof(tmp16));
1219 		b += sizeof(tmp16);
1220 		len -= sizeof(tmp16);
1221 		afi = ntohs(tmp16);
1222 		break;
1223 	case BGP4MP_MESSAGE_AS4_ADDPATH:
1224 	case BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH:
1225 		addpath = 1;
1226 		/* FALLTHROUGH */
1227 	case BGP4MP_MESSAGE_AS4:
1228 	case BGP4MP_MESSAGE_AS4_LOCAL:
1229 		if (len < 12)
1230 			return (0);
1231 		/* source as */
1232 		memcpy(&sas, b, sizeof(sas));
1233 		b += sizeof(sas);
1234 		len -= sizeof(sas);
1235 		sas = ntohl(sas);
1236 		/* dest as */
1237 		memcpy(&das, b, sizeof(das));
1238 		b += sizeof(das);
1239 		len -= sizeof(das);
1240 		das = ntohl(das);
1241 		/* if_index, ignored */
1242 		b += sizeof(tmp16);
1243 		len -= sizeof(tmp16);
1244 		/* afi */
1245 		memcpy(&tmp16, b, sizeof(tmp16));
1246 		b += sizeof(tmp16);
1247 		len -= sizeof(tmp16);
1248 		afi = ntohs(tmp16);
1249 		break;
1250 	default:
1251 		errx(1, "mrt_parse_msg: bad subtype");
1252 	}
1253 
1254 	/* src & dst addr */
1255 	if ((aid = mrt_afi2aid(afi, -1, verbose)) == AID_UNSPEC)
1256 		return (NULL);
1257 
1258 	if ((m = calloc(1, sizeof(struct mrt_bgp_msg))) == NULL)
1259 		err(1, "calloc");
1260 	m->time = t;
1261 	m->src_as = sas;
1262 	m->dst_as = das;
1263 	m->add_path = addpath;
1264 
1265 	if ((r = mrt_extract_addr(b, len, &m->src, aid)) == -1)
1266 		goto fail;
1267 	b += r;
1268 	len -= r;
1269 	if ((r = mrt_extract_addr(b, len, &m->dst, aid)) == -1)
1270 		goto fail;
1271 	b += r;
1272 	len -= r;
1273 
1274 	/* msg */
1275 	if (len > 0) {
1276 		m->msg_len = len;
1277 		if ((m->msg = malloc(len)) == NULL)
1278 			err(1, "malloc");
1279 		memcpy(m->msg, b, len);
1280 	}
1281 
1282 	return (m);
1283 
1284 fail:
1285 	free(m->msg);
1286 	free(m);
1287 	return (NULL);
1288 }
1289